Part 2: (Functions, Closures)

6Functions

6.2.3Functions Without Return Values

func sayGoodbye(personName: String) {

    println("Goodbye, \(personName)!")

}

sayGoodbye("Dave")

// prints "Goodbye, Dave!"


函数是可以没有返回值的,


NOTE

Strictly speaking, the sayGoodbye function does still return a value, even though no return value is defined. Functions without a defined return type return a special value of type Void. This is simply an empty tuple, in effect a tuple with zero elements, which can be written as ().


严格说来,它还是有返回值的,返回void类型,这是个空的tuple,空tuple可以这样写()

所以上面的函数可以这么写

func sayGoodbye(personName: String)->Void {

    println("Goodbye, \(personName)!")

    return ()

}

sayGoodbye("Dave")

// prints "Goodbye, Dave!"


6.2.4Functions with Multiple Return Values


func minMax(array: [Int]) -> (min: Int, max: Int) {

    var currentMin = array[0]

    var currentMax = array[0]

    for value in array[1..<array.count] {//注意 in 后面部分的写法

//    for value in array {//我试过了,这样写也可以

        if value < currentMin {

            currentMin = value

        } else if value > currentMax {

            currentMax = value

        }

    }

    return (currentMin, currentMax)

}


let bounds = minMax([8, -6, 2, 109, 3, 71])

println("min is \(bounds.min) and max is \(bounds.max)")

// prints "min is -6 and max is 109"


利用tuple来一次返回多个值


6.2.5Optional Tuple Return Types


上面的函数如果入参数组个数为0,那么会发生异常。这时应该检查数组个数,当个数是0时,返回nil。所以返回值应该是个可选类型


注意(Int, Int)?(Int?, Int?)的区别


上面的函数修改为:

func minMax(array: [Int]) -> (min: Int, max: Int)? {

    if array.isEmpty { return nil }

    var currentMin = array[0]

    var currentMax = array[0]

    for value in array[1..<array.count] {

        if value < currentMin {

            currentMin = value

        } else if value > currentMax {

            currentMax = value

        }

    }

    return (currentMin, currentMax)

}


6.3.2Shorthand External Parameter Names


If you want to provide an external parameter name for a function parameter, and the local parameter name is already an appropriate name to use, you do not need to write the same name twice for that parameter. Instead, write the name once, and prefix the name with a hash symbol (#). This tells Swift to use that name as both the local parameter name and the external parameter name.


如果参数名本身就非常合适做标签,那么你也不必写两次这个名字,只需在前面加个(#)。这就告诉编译器这个即是参数名,也是标签名。


func containsCharacter(#string: String, #characterToFind: Character) -> Bool {

    for character in string {

        if character == characterToFind {

            return true

        }

    }

    return false

}


let containsAVee = containsCharacter(string: "aardvark", characterToFind: "v")

// containsAVee equals true, because "aardvark" contains a "v"


6.3.3Default Parameter Values


参数默认值

func join(string s1: String, toString s2: String,

    withJoiner joiner: String = " ") -> String {

        return s1 + joiner + s2

}


join(string: "hello", toString: "world", withJoiner: "-")

// returns "hello-world"


join(string: "hello", toString: "world")

// returns "hello world"



6.3.4External Names for Parameters with Default Values


Swift provides an automatic external name for any parameter that has a default value. The automatic external name is the same as the local name, as if you had written a hash symbol before the local name in your code


为参数写标签是很有用的,当没有标签,且参数有默认值时,swift自动为此参数添加与参数名相同的标签,就好像这个参数前面加了(#)似的。


func join(s1: String, s2: String, joiner: String = " ") -> String {

    return s1 + joiner + s2

}


join("hello", "world", joiner: "-")

// returns "hello-world"


join("hello", "world" "-")//Missing argument labell 'joiner:' in call


6.3.5Variadic Parameters


参数个数不定

func arithmeticMean(numbers: Double...) -> Double {

    var total: Double = 0

    for number in numbers {

        total += number

    }

    return total / Double(numbers.count)

}

arithmeticMean(1, 2, 3, 4, 5)

// returns 3.0, which is the arithmetic mean of these five numbers

arithmeticMean(3, 8.25, 18.75)

// returns 10.0, which is the arithmetic mean of these three numbers


NOTE

A function may have at most one variadic parameter, and it must always appear last in the parameter list, to avoid ambiguity when calling the function with multiple parameters.

If your function has one or more parameters with a default value, and also has a variadic parameter, place the variadic parameter after all the defaulted parameters at the very end of the list.


一个函数最多只能有一个variadic parameter,而且为了避免歧义,它必须在最后面

如果函数既有默认值,又有variadic parameter, variadic parameter要在所有默认值后面。




6.3.6Constant and Variable Parameters


函数接收到的参数默认都是常量,这往往要在函数内部定义变量赋值,以便修改

可以通过var 使得接收到的参数自动就是变量



func varParam(var string: String)->String{

    string = string + "aaaa"

    return string;

}


let str1 = "测试"

let str2 = varParam(str1) //"测试aaaa"


6.3.7In-Out Parameters


func swapTwoInts(inout a: Int, inout b: Int) {

    let temporaryA = a

    a = b

    b = temporaryA

}


var someInt = 3

var anotherInt = 107

swapTwoInts(&someInt, &anotherInt)

println("someInt is now \(someInt), and anotherInt is now \(anotherInt)")

// prints "someInt is now 107, and anotherInt is now 3"


要注意的是不仅参数那边要写inout,传参的时候也要在前面加上&



6.4Function Types

func addTwoInts(a: Int, b: Int) -> Int {

    return a + b

}

func multiplyTwoInts(a: Int, b: Int) -> Int {

    return a * b

}

The type of both of these functions is (Int, Int) -> Int.This can be read as:

“A function type that has two parameters, both of type Int, and that returns a value of type Int.”


函数类型:(Int, Int)-> Int


func printHelloWorld() {

    println("hello, world")

}

The type of this function is () -> (), or “a function that has no parameters, and returns Void.” Functions that don’t specify a return value always return Void, which is equivalent to an empty tuple in Swift, shown as ().


函数类型:(Int, Int)-> Int



6.4.1Using Function Types


//var mathFunction: (Int, Int) -> Int = addTwoInts //类型也可以不写

var mathFunction = addTwoInts

println("Result: \(mathFunction(2, 3))")

// prints "Result: 5"


mathFunction = multiplyTwoInts

println("Result: \(mathFunction(2, 3))")

// prints "Result: 6"


定义某种函数类型的变量


6.4.2Function Types as Parameter Types


func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) {

    println("Result: \(mathFunction(a, b))")

}

printMathResult(addTwoInts, 3, 5)

// prints "Result: 8"


函数类型指明参数类型


6.4.3Function Types as Return Types

//定义两个类型为(Int -> Int 的函数

func stepForward(input: Int) -> Int {

    return input + 1

}

func stepBackward(input: Int) -> Int {

    return input - 1

}


//返回值类型为(Int-> Int

func chooseStepFunction(backwards: Bool) -> (Int) -> Int {

    return backwards ? stepBackward : stepForward

}


//根据当前数值判断向0靠近使用哪个函数

var currentValue = 3

let moveNearerToZero = chooseStepFunction(currentValue > 0)

// moveNearerToZero now refers to the stepBackward() function


//执行看下效果

println("Counting to zero:")

// Counting to zero:

while currentValue != 0 {

    println("\(currentValue)... ")

    currentValue = moveNearerToZero(currentValue)

}

println("zero!")

// 3...

// 2...

// 1...

// zero!


6.5Nested Functions


内嵌函数,子函数

func chooseStepFunction(backwards: Bool) -> (Int) -> Int {

    func stepForward(input: Int) -> Int { return input + 1 }

    func stepBackward(input: Int) -> Int { return input - 1 }

    return backwards ? stepBackward : stepForward

}

var currentValue = -4

let moveNearerToZero = chooseStepFunction(currentValue > 0)

// moveNearerToZero now refers to the nested stepForward() function

while currentValue != 0 {

    println("\(currentValue)... ")

    currentValue = moveNearerToZero(currentValue)

}

println("zero!")

// -4...

// -3...

// -2...

// -1...

// zero!




7Closures


Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages.


Closures 与c,oc,lambda中得block相似


Closures can capture and store references to any constants and variables from the context in which they are defined. This is known as closing over those constants and variables, hence the name “closures”. Swift handles all of the memory management of capturing for you.


Closure可以获取并保存上下文中常量变量的引用。

swift会为你做好内存管理



Global and nested functions, as introduced in Functions, are actually special cases of closures.


全局的和内嵌的函数,实际上是closures的特殊形式


Closures take one of three forms:

Closure的3中形式


  • Global functions are closures that have a name and do not capture any values. 
  • 全局函数是有名字的,不获取上下文值的闭包
  • Nested functions are closures that have a name and can capture values from their enclosing function. 
  • 内嵌函数是有名字的,并能获取enclosing funtion中值的闭包
  • Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.

匿名闭包是一种简约写法,可获取上下文的值





7.1Closure Expressions


内嵌函数是自包含代码块的一种简约的形式,然而有时候我们需要连名字都不要的更简约的形式,尤其是把它作为参数的时候


Closure expressions提供多种语法优化来写更简约的closure,下面有sorted函数的closure expression来阐明这些优化形式


7.1.1The Sorted Function


let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]


func backwards(s1: String, s2: String) -> Bool {

    return s1 > s2

}

var reversed = sorted(names, backwards)

// reversed is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]


7.1.2Closure Expression Syntax


reversed = sorted(names, { (s1: String, s2: String) -> Bool in

    return s1 > s2

})


The start of the closure’s body is introduced by the in keyword. This keyword indicates that the definition of the closure’s parameters and return type has finished, and the body of the closure is about to begin.

in前面是定义,后面是实现部分


7.1.3Inferring Type From Context


reversed = sorted(names, { s1, s2 in return s1 > s2 } )


It is always possible to infer the parameter types and return type when passing a closure to a function as an inline closure expression. As a result, you never need to write an inline closure in its fullest form when the closure is used as a function argument.


因为能够推断出参数类型和返回类型,所以不需要写它的完整形式


7.1.4Implicit Returns from Single-Expression Closures


隐式返回

reversed = sorted(names, { s1, s2 in s1 > s2 } )


Here, the function type of the sorted function’s second argument makes it clear that a Bool value must be returned by the closure. Because the closure’s body contains a single expression (s1 > s2) that returns a Bool value, there is no ambiguity, and the return keyword can be omitted.


通过sorted函数的第二个参数知道closure是要返回一个bool值的,而closure实现只包含一个返回bool值的简单的表达式(s1 > s2),所以就没歧义了,return也就可以省略了。


实际上编译器却提示歧义“ Ambiguous use of operator ‘>’”(xcode6.2, Xcode6.1)



7.1.5Shorthand Argument Names


reversed = sorted(names, { $0 > $1 } )

Here, $0 and $1 refer to the closure’s first and second String arguments.


可惜我测试时发现这个式子,编译器也是提示歧义,不过改成下面这样是OK的


reversed = sorted(names, { return $0 > $1 } )


7.1.6Operator Functions


There’s actually an even shorter way to write the closure expression above. Swift’s String type defines its string-specific implementation of the greater-than operator (>) as a function that has two parameters of type String, and returns a value of type Bool. This exactly matches the function type needed for the sorted function’s second parameter. Therefore, you can simply pass in the greater-than operator, and Swift will infer that you want to use its string-specific implementation:


reversed = sorted(names, >)


这是可真是简洁啊,而且测试是通过的,swift v5

偷偷的试了下,这样也是可以的reversed = sorted(names, {return >})


7.2Trailing Closures


If you need to pass a closure expression to a function as the function’s final argument and the closure expression is long, it can be useful to write it as a trailing closure instead. A trailing closure is a closure expression that is written outside of (and after) the parentheses of the function call it supports:


如果函数的最后一个参数是closure,而且你这个closure很长的话,那么你可以把它写成trailing closure,trailing closure意思就是把这个closure写在括号后面。

写在括号后面?把参数写在括号后面?没错,你没看错


比如后这么一个函数

func someFunctionThatTakesAClosure(closure: () -> ()) {

    // function body goes here

}


 你在调用时可以这么写,这是closur参数在括号里面 

// here's how you call this function without using a trailing closure:


someFunctionThatTakesAClosure({

    // closure's body goes here

})


也可以这么写,这是closure参数就在括号外面了 

// here's how you call this function with a trailing closure instead:


someFunctionThatTakesAClosure() {

    // trailing closure's body goes here

}


NOTE

If a closure expression is provided as the function’s only argument and you provide that expression as a trailing closure, you do not need to write a pair of parentheses () after the function’s name when you call the function.

如果这个closure时唯一一个参数,你甚至可以吧括号省了

那么上面的例子就是

someFunctionThatTakesAClosure{} 


The string-sorting closure from the Closure Expression Syntax section above can be written outside of the sorted function’s parentheses as a trailing closure:


比如上面的例子中,可以改成这样子


reversed = sorted(names) { $0 > $1}


编译器不通过,改成这样


reversed = sorted(names) {return $0 > $1}


下面是Array的map方法的一个例子



let digitNames = [

    0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",

    5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"

]

let numbers = [16, 58, 510]


let strings = numbers.map{

    (var number) -> String in

    var output = ""

    while number > 0 {

        output = digitNames[number % 10]! + output

        number /= 10

    }

    return output

}

// strings is inferred to be of type [String]

// its value is ["OneSix", "FiveEight", "FiveOneZero"]


map声明是这样的

/// Return an `Array` containing the results of calling

    /// `transform(x)` on each element `x` of `self`

    func map<U>(transform: (T) -> U) -> [U]



7.3Capturing Values


A closure can capture constants and variables from the surrounding context in which it is defined. The closure can then refer to and modify the values of those constants and variables from within its body, even if the original scope that defined the constants and variables no longer exists.


The simplest form of a closure in Swift is a nested function, written within the body of another function. A nested function can capture any of its outer function’s arguments and can also capture any constants and variables defined within the outer function.


closure能够获取周围上下文中得常量变量值,closure能推算并修改自身函数体中得常量和变量,即使其original scope已不复存在。


下面这个函数makeIncrement嵌套一个子函数increment,

子函数increment可以获取到runningTotal和amount的值

获取到值之后作为makeIncrement函数返回值返回,每次返回的closure被调用将递增amount值


func makeIncrementor(forIncrement amount: Int) -> () -> Int {

    var runningTotal = 0

    func incrementor() -> Int {

        runningTotal += amount

        return runningTotal

    }

    return incrementor

}


返回的是 () -> Int,说明返回的是一个函数,而不是一个简单的数据值


let incrementByTen = makeIncrementor(forIncrement: 10)

incrementByTen()

// returns a value of 10

incrementByTen()

// returns a value of 20

incrementByTen()

// returns a value of 30


let incrementBySeven = makeIncrementor(forIncrement: 7)

incrementBySeven()

// returns a value of 7


incrementByTen()

// returns a value of 40


注意每一个返回的函数都有一套独立的runningTotal


7.4Closures Are Reference Types


Whenever you assign a function or a closure to a constant or a variable, you are actually setting that constant or variable to be a reference to the function or closure.


不管你把函数、closure赋值给常量或是变量,实际上你赋值的是函数、closure的引用


let alsoIncrementByTen = incrementByTen

alsoIncrementByTen()

// returns a value of 50



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值