函数的定义以 func 为前缀,指定的函数的返回类型是以箭头 -> 以及随后类型的名称作为返回的。如下:

func sayHello(personName: String) -> String {
    let greeting = "Hello, " + personName + "!"
    return greeting
}

 

上面这个例子接收一个String参数,返回一个String类型,调用这个函数:

println(sayHello("Anna"))
// prints "Hello, Anna!"
println(sayHello("Brian"))
// prints "Hello, Brian!"

 

为了简化这个函数的主体,结合消息创建和return语句用一行来表示:

func sayHello(personName: String) -> String {
    return "Hello again, " + personName + "!"
}
println(sayHello("Anna"))
// prints "Hello again, Anna!"

 

函数的参数和返回值

 

swift中函数的参数和返回值是非常具有灵活性的。你可以定义任何东西无论是一个简单的仅仅有一个未命名的参数的函数还是那种具有丰富的参数名称和不同的参数选项的复杂函数。

 

多输入参数

函数可以有多个输入参数,把他们写到函数的括号内,并用逗号加以分隔。

func halfOpenRangeLength(start: Int, end: Int) -> Int {
    return end - start
}
println(halfOpenRangeLength(1, 10))
// prints "9"

 

无参函数

函数并没有要求一定要定义的输入参数。下面就一个没有输入参数的函数,任何时候调用时它总是返回相同的字符串消息:

func sayHelloWorld() -> String {
    return "hello, world"
}
println(sayHelloWorld())
// prints "hello, world"

 

无返函数

函数也不需要定义一个返回类型。这里有一个版本的sayHello的函数,称为waveGoodbye,它会输出自己的字符串值而不是函数返回:

func sayGoodbye(personName: String) {
    println("Goodbye, \(personName)!")
}
sayGoodbye("Dave")
// prints "Goodbye, Dave!"

 

因为它并不需要返回一个值,该函数的定义不包括返回箭头( ->)和返回类型。

 

提示:严格地说,sayGoodbye功能确实还返回一个值,即使没有返回值定义。函数没有定义返回类型但返 回了一个void返回类型的特殊值。它是一个简直是空的元组,实际上零个元素的元组,可以写为()。

 

当一个函数调用时它的返回值可以忽略不计:

func printAndCount(stringToPrint: String) -> Int {
    println(stringToPrint)
    return countElements(stringToPrint)
}
func printWithoutCounting(stringToPrint: String) {
    printAndCount(stringToPrint)
}
printAndCount("hello, world")
// prints "hello, world" and returns a value of 12
printWithoutCounting("hello, world")
// prints "hello, world" but does not return a value

 

提示:返回值可以忽略,但一个定义了返回值的函数则必须有返回值。如果一个函数定义了返回值,在函数结束之前如果没有返回值,那么将会出现一个编译时错误。

 

多返回值函数

你可以使用一个元组类型作为函数的返回类型,来返回一个由多个值组成的复合返回值。

下面的例子定义了一个名为count函数,用它计来算字符串中基于标准的美式英语中设定使用的元音、辅音以及字符的数量:

func count(string: String) -> (vowels: Int, consonants: Int, others: Int) {
    var vowels = 0, consonants = 0, others = 0
    for character in string {
        switch String(character).lowercaseString {
        case "a", "e", "i", "o", "u":
            ++vowels
        case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
        "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
        ++consonants
        default:
        ++others
        }
    }
    return (vowels, consonants, others)
}

 

您可以使用此计数函数来对任意字符串进行字符计数,并检索统计总数的元组三个指定Int值:

let total = count("some arbitrary string!")
println("\(total.vowels) vowels and \(total.consonants) consonants")
// prints "6 vowels and 13 consonants"

 

函数参数名

所有上面的函数都为参数定义了参数名称:

func someFunction(parameterName: Int) {
    // function body goes here, and can use parameterName
    // to refer to the argument value for that parameter
}

 

然而,这些参数名的仅能在函数本身的主体内使用,在调用函数时,不能使用。这些类型的参数名称被称为本地的参数,因为它们只适用于函数体中使用。

 

外部参数名

有时当你调用一个函数将每个参数进行命名是非常有用的,以表明你传递给函数的每个参数的目的。

如果你希望用户函数调用你的函数时提供参数名称,除了设置本地地的参数名称,也要为每个参数定义外部参数名称。你写一个外部参数名称在它所支持的本地参数名称之前,之间用一个空格来分隔:

简单说就是在调用函数的时候要指明参数名,声明这样一个函数的格式:

func someFunction(外部参数名 本地参数名: Int) {
    // function body goes here, and can use localParameterName
    // to refer to the argument value for that parameter
}

 

提示:如果您为参数提供一个外部参数名称,调用该函数时必须指定外部参数名。

作为一个例子,考虑下面的函数,它通过插入他们之间的第三个"joiner"字符串来连接两个字符串:

func join(s1: String, s2: String, joiner: String) -> String {
    return s1 + joiner + s2
}

当你调用这个函数,你传递给函数的三个字符串的目的就不是很清楚了:

join("hello", "world", ", ")
// returns "hello, world"

为了使这些字符串值的目的更为清晰,为每个join函数参数定义外部参数名称:

func join(string s1: String, toString s2: String, withJoiner joiner: String) -> String {
    return s1 + joiner + s2
}

在这个版本的join函数中,第一个参数有一个外部名称string和一个本地名称s1;第二个参数有一个外部名称toString和一个本地名称s2;第三个参数有一个外部名称withJoiner和一个本地名称joiner

现在,您可以使用这些外部参数名称调用清楚明确的调用该函数:

join(string: "hello", toString: "world", withJoiner: ", ")
// returns "hello, world"

 

外部参数名称速记

如果你想为一个函数参数提供一个外部参数名,然而本地参数名已经使用了一个合适的名称了,你不需要为该参数写相同的两次名称。取而代之的是,写一次名字,并用一个hash符号()作为名称的前缀。这告诉Swift使用该名称同时作为本地参数名称和外部参数名称。

这个例子定义了一个名为containsCharacter的函数,定义了两个参数的外部参数名称并通过放置一个散列标志在他们本地参数名称之前:

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"

 

参数的默认值

可以为任何参数设定默认值来作为函数的定义的一部分。如果已经定义了默认值,调用函数时就可以省略该参数的传值。

提示将使用默认值的参数放在函数的参数列表的末尾。这确保了所有调用函数的非默认参数使用相同的顺 序,并明确地表示在每种情况下相同的函数调用。

这里有一个版本,是早期的join函数,并为参数joiner设置了默认值:

func join(string s1: String, toString s2: String,
    withJoiner joiner: String = " ") -> String {
        return s1 + joiner + s2
}

如果在join函数被调用时提供给joiner一个字符串值,该字符串是用来连接两个字符串,就跟以前一样:

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

但是,如果当函数被调用时没有提供joiner的值,就会使用单个空格(" ")的默认值:

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

 

有默认值的外部名称参数

这里有一个早期join函数版本,它不为任何参数提供的外部名称,但仍然提供了joiner参数的默认值:

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

在这种情况下,Swift自动为一个具有默认值的参数提供了外部参数名称。调用函数时,为使得参数的目的明确、毫不含糊,因此必须提供外部名称:

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

 

可变参数

写可变参数的参数时,需要参数的类型名称后加上点字符(...)。

对于可变参数的值,函数体中是以数组的形式存在。例如,一个可变参数的名称为numbers和类型为Double...在函数体内就作为名为numbers类型为Double[]的常量数组。

下面的示例计算任意长度的数字的算术平均值(也称为平均):

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, 19)
// returns 10.0, which is the arithmetic mean of these three numbers

 

提示:函数最多只能有一个可变参数,而且它必须出现在参数列表的最后以避免多参数函 数调用时出现歧义。如果函数有一个或多个参数使用默认值,并且还具有可变参数,将可变参数放在列表的 最末尾的所有默认值的参数之后。

 

常量参数和变量参数

函数参数的默认值都是常量。试图改变一个函数参数的值会让这个函数体内部产生一个编译时错误。这意味着您不能错误地改变参数的值。

在参数名称前用关键字var定义变量参数:

func alignRight(var string: String, count: Int, pad: Character) -> String {
    let amountToPad = count - countElements(string)
    for _ in 1...amountToPad {
        string = pad + string
    }
    return string
}
let originalString = "hello"
let paddedString = alignRight(originalString, 10, "-")
// paddedString is equal to "-----hello"
// originalString is still equal to "hello"

 

提示:一个变量参数的变化没有超出了每个调用函数,所以对外部函数体是不可见的。变量参数只能存在于函数调用 的生命周期里。

 

输入-输出参数

可变参数,如上所述,只能在函数本身内改变。如果你想有一个函数来修改参数的值,并且想让这些变化要坚持在函数调用结束后,你就可以定义输入-输出参数来代替。

通过在其参数定义的开始添加inout关键字写用来标明输入-输出参数,

参数列表中只可以传递一个变量作为一个in-out参数。不能传递一个常数或常值作为参数,因为常量和文字不能修改。你直接在变量名前放置一个连字符(),当你把它作为一个参数传递给一个in-out参数,表明它可以通过该功能进行修改。

 

提示:in-out参数不能有默认值,可变参数的参数也不能被标记为inout。如果您标记参数为inout,它不能同时被标记为varlet

这里的一个叫做swapTwoInts函数,它有两个称为a和b的输入-输出整数参数:

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"

 

提示:输入输出参数与从函数返回的值是不一样的。上述swapTwoInts例子没有定义返回类型或返回一个值,但它仍然会修改someIntanotherInt的值。

 

函数类型

 

每一个函数都有特定的函数类型,可以充当参数类型和函数的返回类型。

简单说,就是可以将一个函数作为参数传递也可以作为一个函数值返回。

 

使用函数类型

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

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

func printHelloWorld() {
    println("hello, world")
}

var mathFunction: (Int, Int) -> Int = addTwoInts

 

可以解读为:

"定义一个名为mathFunction变量,该变量的类型为'一个函数,它接受两个int值,并返回一个int值。'设置这个新的变量来引用名为addTwoInts功能。"

调用它:

println("Result: \(mathFunction(2, 3))")
// prints "Result: 5"

 

当你为常量或变量分配一个函数时,Swift会自动推断为函数类型:

let anotherMathFunction = addTwoInts
// anotherMathFunction is inferred to be of type (Int, Int) -> Int

 

函数类型的参数

将函数作为参数传递:

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

func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) {
    println("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// prints "Result: 8"

这个例子中定义了一个名为printMathResult函数,它有三个参数。第一个参数名为mathFunction,类型为(Int, Int)->Int。您可以传入符合的任何函数类型作为此函数的第一个参数。第二和第三个参数ab都是int类型。被用作用于提供数学函数的两个输入值。

printMathResult被调用时,它传递addTwoInt函数,以及整数值3和5。它调用的值3和5所提供的功能,并打印8的结果。

printMathResult的作用是调用一个适当类型的数学函数并打印相应结果。那是什么功能的实现其实并不重要,你只要给以正确的类型匹配就行。这使printMathResult以调用者类型安全的方式转换了函数的功能。

 

函数类型的返回值

使用一个函数类型作为另一个函数的返回值

下面的例子定义了两个简单的函数调用stepForwardstepBackward。该stepForward函数返回一个值高于其输入值,而stepBackward函数返回一个值低于其输入值。这两个函数都有一个相同的类型 (Int) -> Int

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

 

这里有一个chooseStepFunction函数。chooseStepFunction返回一个 ‘参数为Int返回也是Int的函数’(Int)->Int(比较拗口)

func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
    return backwards ? stepBackward : stepForward
}

您现在可以使用chooseStepFunction获取一个函数,可能是加一函数或是减一函数:

var currentValue = 3
let moveNearerToZero = chooseStepFunction(currentValue > 0)
// moveNearerToZero 的类型是 setpBackward

currentValue初始值是3,这意味着currentValue >0,则返回truechooseStepFunction返回stepBackward函数。返回函数的引用存储在一个称为moveNearerToZero常量里。

如今moveNearerToZero执行了正确的功能,就可以用来计数到零:

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!

 

嵌套函数

迄今为止所有你在本章中遇到函数都是全局函数,在全局范围内定义。其实你还可以在其他函数中定义函数,被称为嵌套函数。

重写上面的chooseStepFunction例子使用并返回嵌套函数:

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!

 

来源

 

2015-03-20

13:57:22

posted on 2015-03-20 13:58  道无涯  阅读(179)  评论(0编辑  收藏  举报