import
 
class ViewController:  UIViewController
   
override func
    super.viewDidLoad()
     
/**

     变量参数只能在函数体内被修改。

     如果需要一个函数可以修改参数值,并且这些修改在函数调用结束后仍然生效,那么就把这个参数定义为输入输出参数(In-Out Parameters)。

     通过在参数前加 inout 关键字定义一个输入输出参数。

     输入输出参数值被传入函数,被函数修改,然后再被传出函数,原来的值将被替换。

     输入输出参数不能有默认值,不能是可变参数。

     

如果一个参数被 inout 标记,这个参数就不能被 var 或 let 标记。

*/
func triangle(inout a:Int,inout b:Int) ->Int{
       
       a = a * a
       b = b * b
      print("a == \(a) and b== \(b)")
return
       
     }
var c = 3
var d = 4
/**

    只能传入一个变量作为输入输出参数。

    不能传入常量或者字面量(literal value),因为这些值是不允许被修改的。

    当传入的实参作为输入输出参数时,需要在实参前加 & 符,表示这个值可以被函数修改。

    否则会报错

    c 和 d这两个参数在传入triangle这个参数时,都必须加前缀&

*/
print(triangle(&c, b: &d))
print(triangle(&c, b: &d))
/**

     输入输出参数是函数对函数体外产生影响的另一种方式

     每个函数都有特定的类型,由函数的参数类型和返回类型组成

*/
func addTwoInts(a:Int,b:Int)->Int{
       
return
       
     }
func mutiplyTwoInts(a:Int,b:Int)->Int{
       
return
       
     }
/**

以上定义了两个函数:addTwoInts 和 multiplyTwoInts。

     他们都有两个 Int 类型参数, 都返回一个 Int 类型值。

这两个函数的类型是 (Int, Int) -> Int,

     可以读作 “有2个Int类型参数,返回Int类型值的函数类型”

*/
func
       
      print("hello world")
       
     }
/**

这个函数的类型是: () -> () ,

     可以读作“没有参数,没有返回值(或者返回 Void)的函数类型”。

     没有指定返回值类型的函数总是返回 Void。

在Swift中,Void 与空的元组是一样的

     使用函数类型就像使用其他类型一样。

     例如,你可以定义一个类型为函数的常量或变量,并将函数赋值给它

  

*/
var mathPlus:(Int,Int)->Int = addTwoInts
     
print("\(mathPlus(2,3))")
     
     //有相同函数类型的不同函数可以被赋值给同一个变量,就像非函数类型的变量一样
     
mutiplyTwoInts
     
print("\(mathPlus(2,3))")
     
     //像其他非函数类型一样,当给常量或变量赋值一个函数时,Swift 会推测其函数类型:
let
     
print("\(another(3,4))")
     
/**

     像其他类型一样,函数类型可以作为参数。

     这样可以将函数的一部分功能交给给函数类型的参数。

比如用(Int, Int) -> Int 的函数类型作为另一个函数的参数类型

*/
     
func addTwoIntsMath(a:Int,b:Int)->Int{
       
return
       
     }
     
var mathPlusMath:(Int,Int)->Int = addTwoIntsMath
     
func printMathResult(mathFuncion:(Int,Int)->Int, a:Int, b:Int){
       
print("result : \(mathFuncion(a,b))")
       
     }
     
    printMathResult(addTwoIntsMath, a: 3, b:  5)
printMathResult(mathPlusMath, a:  4, b: 6)
     
/**

函数 printMathResult 有三个参数:第一个参数叫 mathFunction,类型是(Int, Int) -> Int

     第二个和第三个参数叫 a 和 b,它们的类型都是 Int 。

当 printMathResult 被调用时,传入参数: addTwoInts 函数、整数3和5。

函数内部调用 mathPlus 函数,这时又把a,b作为参数传给mathPlus并返回结果8

     

最后在是8,输出结果 8
      */
      
/**
     函数类型也可以作为另一个函数的返回值类型。
     就是在返回箭头(->)后写一个完整的函数类型。
      
      */
func plusOne(plus:Int)->Int{
       
return plus +  1
       
     }
func reduceOne(reduce:Int)->Int{
       
return reduce -  1
       
     }
     
func chooseOne(plusOrReduce:Bool)->(Int)->Int{
       
return plusOrReduce ?  reduceOne : plusOne
       
     }
     
    //    var currentValue = 3 //打印是2
var currentValue = -5 //打印是-2
     
    //这个moveNearerToZero是一个函数 可能是reduceOne  也可能是plusOne
let moveNearerToZero =  chooseOne(currentValue > 0)
     
print("\(moveNearerToZero(currentValue))")
     
while currentValue !=  0
       
       currentValue = moveNearerToZero(currentValue)
print("currentValue==  \(currentValue)")
       
       
     }
/**

定义在全局域中的所有函数都是全局函数(global functions)

     当然函数也可以被定义在别的函数体中,称作嵌套函数(nested functions)。

     

     默认情况下,嵌套函数是对外是不可见的,

但可以被封闭他们的函数(enclosing function)调用。

     封闭函数可以返回它的一个嵌套函数,使这个函数在其他域中可以被使用。

用返回嵌套函数的方式重写以上例子
      */
     
func chooseOne1(plusOrReduce:Bool)->(Int)->Int{
       
func plus1(a:Int)->Int{
return a +  1
       }
       
func reduce1(a:Int)->Int{
return a -  1
       }
       
return plusOrReduce ?  reduce1 : plus1
       
     }
     
var currentValue1 = -4
let moveNearerToZero1 =  chooseOne1(currentValue1 > 0)
while currentValue1 !=  0
       
       currentValue1 = moveNearerToZero1(currentValue1)
print("currentValue1== \(currentValue1)")
       
     }
     
   }
   
 }