【Swift 3.1】06 - 方法 (Functions)

方法 (Functions)

自从苹果2014年发布Swift,到现在已经两年多了,而Swift也来到了3.1版本。去年利用工作之余,共花了两个多月的时间把官方的Swift编程指南看完。现在整理一下笔记,回顾一下以前的知识。有需要的同学可以去看官方文档>>


声明和调用方法 (Defining and Calling Functions)

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

使用func来声明方法,greet是方法名,person是参数名(也是标签名),String是参数类型,->来指定返回值类型。

方法的参数和返回值 (Function Parameters and Return Values)

无参数的方法 (Functions Without Prameters)
func sayHelloWorld() -> String {
    return "hello, world"
}
print(sayHelloWorld())
// Prints "hello, world"
有多个参数的方法 (Function With Multiple Parameters)
func greet(person: String, alreadyGreeted: Bool) -> String {
    if alreadyGreeted {
        return greetAgain(person: person)
    } else {
        return greet(person: person)
    }
}
print(greet(person: "Tim", alreadyGreeted: true))
// Prints "Hello again, Tim!"
无返回值的方法 (Functions Without Return Values)
func greet(person: String) {
    print("Hello, \(person)!")
}
greet(person: "Dave")
// Prints "Hello, Dave!"

因为参数没有返回值,所以方法的定义不包含->和返回类型。

注意:严格地说,这个方法还是有一个返回值,即使没有定义返回类型。没有定义返回值的方法返回一个Void类型的值,这个返回值是一个空多元组()

方法被调用之后,返回值可以忽略:

func printAndCount(string: String) -> Int {
    print(string)
    return string.characters.count
}
func printWithoutCounting(string: String) {
    let _ = printAndCount(string: string)
}
printAndCount(string: "hello, world")
// prints "hello, world" and returns a value of 12
printWithoutCounting(string: "hello, world")
// prints "hello, world" but does not return a value
返回多个值的方法 (Functions with Multiple Return Values)

使用多元组作为返回值,来返回多个值:

fun mixMax(array: [Int]) -> (min: Int, max: Int) {
    var currentMix = array[0]
    var currentMax = array[1]
    for value in array[1..<arry.count] {
        if value < currentMix {
            currrentMix = value
        }
        else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMix, currentMax)
}

let bounds = mixMax(array: [8, -6, 2, 109, 3, 71])
print("min is (bounds.min), and max is \(bounds.max)")
// Prints "min is -6 and max is 109"

再返回多元组的时候,不用再给元素命名,因为方法的返回值已经命名。

可选多元组返回类型 (Optional Tuple Return Types)

如果方法返回的多元组有可能没有值,我们在定义方法返回值时可以使用可选类型,例如(Int, Int)?(String, Int, Bool)?

注意:(Int, Int)?多元组可选类型不同于包含可选类型元素的多元组(Int?, Int?)(Int, Int)?多元组是可选类型,而(Int?, Int?)其中的元素才是可选了类型。

方法参数标签和参数名 (Function Argument Labels and Parameter Names)

每个方法的参数都有一个参数标签和参数名。参数标签使你在调用方法的时候使用,参数名实在方法实现里调用。默认情况下,参数表前和参数名是相同的。

func someFunction(firstParameterName: Int, secondParameterName: Int) {
    // In the function body, firstParameterName and secondParameterName
    // refer to the argument values for the first and second parameters.
}
someFunction(firstParameterName: 1, secondParameterName: 2)

所有的参数名必须是唯一的,参数标签有可能相同。但是为了提高代码的可读性,参数标签唯一可以提高代码的可读性。

指定参数标签 (Specifying Argument Labels)

把参数标签写在参数名前面:

func someFunction(argumentLabel parameterName: Int) {
    // In the function body, parameterName refers to the argument value
    // for that parameter.
}

例如:

func greet(person: String, from hometown: String) -> String {
    return "Hello \(person)!  Glad you could visit from \(hometown)."
}
print(greet(person: "Bill", from: "Cupertino"))
// Prints "Hello Bill!  Glad you could visit from Cupertino."

使用参数标签,调用方法就像调用一个句子一样,非常清晰,可读性非常高。

删除参数标签 (Omitting Argument Labels)

如果我们不需要参数标签,使用_来代替参数标签:

func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
    // In the function body, firstParameterName and secondParameterName
    // refer to the argument values for the first and second parameters.
}
someFunction(1, secondParameterName: 2)

如果一个参数有标签,在调用方法时必须写标签。

参数默认值 (Default Parameter Values)

在声明方法时,可以给参数一个默认值:

func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
    // If you omit the second argument when calling this function, then
    // the value of parameterWithDefault is 12 inside the function body.
}
someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) // parameterWithDefault is 6
someFunction(parameterWithoutDefault: 4) // parameterWithDefault is 12
可变参数 (Variadic Parameters)

一个可变参数可以接受0个或多个指定类型的值。使用可变参数来指定这个参数在方法调用时可以被传入多个值,
传入方法的多个值在方法体中会作为一个数组。:

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

注意:一个方法最多只能有一个可变参数。

In-Out 参数 (In-Ont Parameters)

方法的参数默认情况下是属于常量,在方法中是不能改为参数值的。如果我们想在一个方法中改变参数的值,并且在方法执行完之后保持改变,应该把参数定义为in-out参数。

使用inout关键字来定义一个in-out参数,把inout放在参数类型的前面。对于in-out参数,在方法调用时,我们只能传入变量,不能传入常量或者字面值,因为常量和字面值是不能修改的。把变量传给一个参数时,要在变量名前面写一个&,来提示它是可以变改变的。

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let tempA = a
    a = b
    b = tempA
}

var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// Prints "someInt is now 107, and anotherInt is now 3"

方法类型 (Function Types)

每个方法都有一个特定的方法类型,并且由参数类型和返回值类型组成。

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

这两个方法的类型都是(Int, Int) -> Int,可以这么理解:这个方法有两个Int类型的参数,返回一个Int类型的值。

下面是一个没有参数的方法:

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

这个方法的类型是() -> Void

使用方法类型 (Using Function Types)
var mathFunction: (Int, Int) -> Int = addTwoInts

可以理解为:定义一个mathFunction变量,这个变量的类型是有两个Int类型参数并返回值为Int类型的方法,然后把这个变量指向addTwoInts

使用mathFunction方法:

print("Result: \(mathFunction(2, 3))")
// Prints "Result: 5"

类型相同的不同方法可以赋值给同一个变量,例如:

mathFunction = multiplyTwoInts
print("Result: \(mathFunction(2, 3))")
// Prints "Result: 6"
方法类型作为参数类型 (Function Types as Parameter Types)

我们可以使用方法类型作为参数类型。例如:

func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
    print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// Prints "Result: 8"
方法类型作为返回值类型 (Function Types as Return Types)
func stepForward(_ input: Int) -> Int {
    return input + 1
}
func stepBackward(_ input: Int) -> Int {
    return input - 1
}

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

使用chooseStepFunction(backward:)方法来选择前进的方向:

var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero now refers to the stepBackward() function

moveNearerToZero已经引用了一个正确的方法,可以让一个值越来越接近0:

print("Counting to zero:")
while currentValue != 0 {
    print("\(currentValue)...")
    currentValue = moveNearToZero(currentValue)
}
print("zero!")
// 3...
// 2...
// 1...
// zero!

嵌套方法 (Nested Functions)

目前所接触到的所有方法都是在全局区域定义的全局方法。其实我们还可以在一个方法内部定义其他方法。嵌套的方法默认情况下,外面是访问不到的,只有包含这个嵌套方法的方法内部才可访问。但是包含嵌套方法的方法可以把其嵌套方法作为返回值供外面使用,所以上面的chooseStepFunction(backward:)可以改写为:

func chooseStepFunction(backward: Bool) -> (Int) -> Int {
    func stepForward(input: Int) -> Int { return input +1 }
    func stepBackward(input: Int) -> Int { return input - 1 }
    return backward ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero now refers to the nested stepForward() function
while currentValue != 0 {
    print("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// -4...
// -3...
// -2...
// -1...
// zero!

第六部分完。下个部分:【Swift 3.1】07 - 闭包 (Closures)


如果有错误的地方,欢迎指正!谢谢!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容