美文网首页iOS知识点swift 一起修炼swift
一个下午让你掌握Swift基础 ( 7/9 ) 函数

一个下午让你掌握Swift基础 ( 7/9 ) 函数

作者: 张嘉夫 | 来源:发表于2016-07-14 00:38 被阅读1454次

    简介

    这是一个Swift语言教程,基于最新的iOS 9,Xcode 7.3和Swift 2.2,会为你介绍Swift编程非常基础的内容。从电脑如何工作的全程基本原理到语言结构,你会足够了解这门语言,来处理数据和管理代码的行为。

    快速链接


    函数

    函数(Functions)是很多编程语言的核心。简单地说,一个函数让你定义一个代码块来完成指定的任务。然后,无论何时 app 需要执行这个任务,都可以运行这个函数,而不是到处复制和粘贴同样的代码。

    这篇文章里,你会学习到如何写自己的函数,以及亲眼目睹 Swift 如何让他们轻松使用。

    函数基础

    假设你有一个 app 经常需要打印名字。你可以写一个函数来实现:

    func printMyName() {
        print("我的名字是张嘉夫。")
    }
    

    上面的代码被称作函数声明(function declaration)。你用 func 关键字来定义一个函数。接着是函数的名字,跟着括号。你会在下个部分学习更多有关这些括号的必要性。

    括号之后跟着一个开的花括号,后面是你想在函数里运行的代码,跟着一个关闭的花括号。函数定义好之后,你可以这样使用它:

    printMyName()
    

    这输出如下内容:

    我的名字是张嘉夫。
    

    如果你怀疑你在之前的文章里已经使用了一个函数,那就对啦!print, 在控制台里输出你给它的文本,事实上就是一个函数。

    这很好地引向了下个部分,你会在那里学习如何传递数据给一个函数,以及获得返回的数据。

    函数参数

    在之前的例子里,函数简单地输出了一条消息。这很棒,但有的时候你希望参数化(parameterize)你的函数,这可以让函数进行不同的操作,依据通过它的参数(parameters)传递进来的数据。

    举个例子,看下面的函数:

    func printMultipleOfFive(multiplier: Int) {
        print("\(multiplier) * 5 = \(multiplier * 5)")
    }
    printMultipleOfFive(10)
    

    这里,你能看到一个参数的定义,在函数名后面的括号里。它叫做 multiplier,是 Int 类型的。在所有函数里,括含包含被称作参数列表(parameter list)的东西。

    函数会输出给的任意值的5倍。这个例子里,你可以带有 10 的值来调用函数,所以函数如下输出:

    10 * 5 = 50
    

    你可以更进一步,让函数更通用。带有两个参数,函数可以输出任意两个值的乘积。你可以这样做:

    func printMultipleOf(multiplier: Int, andValue: Int) {
        print("\(multiplier) * \(andValue) = \(multiplier * andValue)")
    }
    printMultipleOf(4, andValue: 2)
    

    现在函数名字后面的括号里有两个参数了:一个叫做 multiplier 并且另一个叫做 andValue。两个都是 Int 类型。

    这次,你调用函数的时候传递了两个值。注意第二个参数之前有一个标签。这个语法是 Swift 的方式,让你写的代码读起来就像一个句子。上面的例子里,你会像这样读最后一行代码:

    Print multiple of 4 and value 2
    

    你可以让它阅读起来更清晰,通过给一个参数不同的外置(external)名字。
    例如,你可以像这样改变 andValue 参数的外置名字:

    func printMultipleOf(multiplier: Int, and andValue: Int) {
        print("\(multiplier) * \(andValue) = \(multiplier * andValue)")
    }
    printMultipleOf(4, and: 2)
    

    你分配了一个不同的外置名字,通过把它写在参数名前面。
    这个例子里,andValue 仍然是参数的名字,但调用函数的标签现在简写为 and 了。你可以这样读新的调用:

    Print multiple of 4 and 2
    

    如果你根本不想要任何外置名字,那可以用下划线 _,就像你在前面的文章里见到的:

    func printMultipleOf(multiplier: Int, _ andValue: Int) {
        print("\(multiplier) * \(andValue) = \(multiplier * andValue)")
    }
    printMultipleOf(4, 2)
    

    这个例子里,第二个参数没有外置名字,就像第一个参数。但要明智的使用下划线。这里,你的表达仍然可以理解,但带有很多参数的更复杂的函数会变得费解、笨重,如果它没有外置名字的话。想象一下一个带有5个参数的函数!

    你也可以给参数默认值:

    func printMultipleOf(multiplier: Int, and andValue: Int = 1) {
        print("\(multiplier) * \(andValue) = \(multiplier * andValue)")
    }
    printMultipleOf(4)
    

    区别是第二个参数后面的 =1,意味着如果第二个参数没有给值,默认就是1。

    因此,代码如下输出:

    4 * 1 = 4
    

    如果你预料大部分时间一个参数都是一个值,那有一个默认值会是很有用的,并且它会简化你调用函数的代码。

    返回值

    你到目前为止看到的所有函数都执行一个简单的任务,其实也就是,输出一些东西。函数也能返回一个值。函数的调用者可以把返回值(return value)赋值给一个变量或常量。

    这意味着你可以用一个函数来处理数据。通过参数来带进数据,操作它然后返回它。这是定义一个返回值的函数的方法:

    func multiply(number: Int, by byValue: Int) -> Int {
        return number * byValue
    }
    let result = multiply(4, by: 2)
    

    要声明一个返回值的函数,在一对括号和打开的花括号中间,添加一个 -> 紧跟着返回值的类型。这个例子里,函数返回一个 Int。

    函数里面,使用 return 关键词来返回值。这个例子里,你返回了两个参数的乘积。

    通过使用元祖也可以返回多个值:

    func multiplyAndDivide(number: Int, by byValue: Int) -> (multiply: Int,
        divide: Int) {
            return (number * byValue, number / byValue)
    }
    let result = multiplyAndDivide(4, by: 2)
    let multiply = result.multiply
    let divide = result.divide
    

    这个函数返回了两个参数的乘积和商。我们定义了函数返回一个元祖,这个元祖包含两个 Int 值,并且带有合适的成员值名称,实现了这个结果。

    通过元祖返回多个值的能力让使用 Swift 变得很快乐。并且它被证明是一个非常有用的特色,你马上就会看到。

    高级参数管理

    传递给函数的参数默认是常量,意味着他们不能被修改。举例说明,看如下代码:

    func incrementAndPrint(value: Int) {
        value += 1
        print(value)
    }
    

    这会导致一个错误:

     Left side of mutating operator isn't mutable: 'value' is a 'let' constant(修改操作符左侧没法被修改:'value‘ 是一个 'let' 常量)
    

    参数 value 等同于一个用 let 声明的常量。因此,当函数尝试递增它的时候,编译器抛出了一个错误。

    要知道 Swift 在值传递给函数之前拷贝了它,一个行为叫做 pass-by-value

    **注意:**Pass-by-value 和做拷贝是目前为止你在本教程中看到的所有类型的标准行为。你会在后面的教程看到另一种方式,把东西传递到函数中,“类”。

    通常情况下你想要这个行为。理想情况下,一个函数不会修改它的参数。如果它这么做了,然后你就不能确定参数的值,代码里可能会出现错误的假设,导致了错误的数据。

    有时候你的确希望让一个函数直接改变一个参数,一个行为叫做 pass-by-reference。像这样做:

    func incrementAndPrintInOut(inout value: Int) {
        value += 1
        print(value)
    }
    

    参数名前的 inout 关键字表示这个参数应该使用 pass-by-reference。

    现在你需要给函数调用做一个轻微调整:

    var value = 5
    incrementAndPrintInOut(&value)
    print(value)
    

    你在参数前加了个 & 符号,帮助你记住这个参数用的是 pass-by-reference。现在函数可以随心所欲改变值。

    这个例子会如下输出:

    6
    6
    

    函数成功递增了 value,在函数结束后还保留了被修改的数据。这就像参数进入(in)了函数,然后又出来了(out),因此是关键词 inout。

    标准库的例子

    Swift 标准库包含很多准备好的函数供你使用。

    你在读本教程的时候已经看见有一个被使用了:print。它携带一个单独的字符串参数,把它输出到控制台。

    有一些数学函数值得记忆因为他们经常在手边使用:

    第一个就是 max,带有两个值,返回最大值:

    let result = max(10, 20)
    

    这个例子里,result 等于 20。

    相似的,min 带有两个值,返回最小值:

    let result = min(10, 20)
    

    这里,result 等于 10。

    最后,abs 带有一个单独的值然后返回绝对值。例如,-10 的绝对值是 10,10 的绝对值是 10。这是 Swift 函数:

    let result = abs(-10)
    

    这次,result 等于 10。

    当你继续使用 Swift 的时候,你会遇到标准库里的许多其它函数。你不会记住所有的,但重要的是知道存在有很多预定义的函数。如果你觉得可能有一个是为你要做的事准备的,就搜索它。如果 Apple 已经写了一个被完全测试过的函数,那就没必要再重复劳动了!

    迷你练习

    1. 写一个叫 printFullName 函数,带有两个字符串,叫做 firstName 和 lastName。函数应该输出全名,定义为 firstName + " " + lastName。用它来输出你自己的全名。
    2. 改变 printFullName 的声明,让它的第二个参数 lastName 没有外置名字。
    3. 写一个叫做 calculateFullName 的函数,把全名用字符串(string)返回。用它把你自己的名字保存为一个常量。
    4. 改变 calculateFullName 返回一个元祖,包含全名和名字的长度。你可以用下面的语法来获得一个字符串的长度:string.characters.count。用这个函数来确定你自己全名的长度。

    函数作为变量

    这可能会让人吃惊,但 Swift 里的函数只是简单的另一种数据类型而已。你可以给它们赋值变量和常量,就像你可以对任意其它值的类型一样,比如 Int 或 String。

    要知道怎么用,看下面的函数:

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

    它带有两个参数,返回他们的和。

    你可以把这个函数赋值给一个变量,像这样:

    var function: (Int, Int) -> Int = add
    

    这里,变量名是 function 并且它的类型是(Int, Int) -> Int。你把 add 函数赋值给这个变量。

    然而类型定义很重要。你用函数定义里同样的方式来定义变量,写参数列表和返回类型。这里 function 变量是一个函数类型,带有两个 Int 参数并且返回一个 Int。

    现在你可以用 function 变量,和使用 add 同样的方式,像这样:

    let result = function(4, 2)
    

    这个例子里,result 等于 6。

    现在看看下面的代码:

    func subtract(a: Int, _ b: Int) -> Int {
        return a - b
    }
    

    现在,你定义了另一个函数,带有两个 Int 参数并且返回一个 Int。你可以设置之前的 function 变量为你的新 subtract 函数,因为 subtract 的参数列表和返回类型和 function 变量的类型是匹配的。

    function = subtract
    let result = function(4, 2)
    

    这次,result 等于 2。

    “可以把函数赋值给变量”会经常在手边用,是因为它意味着你可以传递函数给其他函数。这是它的实际例子:

    func printResult(function: (Int, Int) -> Int, _ a: Int, _ b: Int) {
        let result = function(a, b)
        print(result)
    }
    printResult(add, 4, 2)
    

    printResult 带有三个参数:

    1. function 是一个函数类型,带有两个 Int 参数并且返回一个 Int,像这样声明:(Int, Int) -> Int。
    2. a 没有外置名字,并且类型是 Int。
    3. b 没有外置名字,并且类型是 Int。
      printResult 调用了传入的函数,传给它两个 Int 参数。
      然后它输出结果到控制台:

    6

    能够传递函数给其它函数是非常实用的,可以帮助你写可复用代码。你不止可以传递数据来操作,函数作为参数传递让你把代码如何执行变得更灵活。

    关键点

    • 使用函数(function)来定义一个任务,想执行多少次都可以,不需要多次写代码。
    • 函数可以带有零或更多参数(parameters),并且可以选择性返回一个值。
    • 函数的第一个参数在函数调用里没有标签(label)。所有随后的参数用他们的名字作为标签。
    • 你可以添加一个外置名字(external name)给一个函数参数,来改变函数调用里使用的标签,或者你可以用一个下划线来表示没有标签。
    • 你可以赋值函数给变量,然后传递他们给其它函数。

    接下来去哪儿?

    函数是组合小的代码块到大的单元的第一步。你会继续这个主题,在下面的文章里学习集合类型(collection types)和结构体(structures)。
    在下一篇文章你会学习闭包(closures),和函数相关但更轻量、在“百忙中”也可以轻松声明。继续之前,看看前面的挑战,因为你在理解闭包之前需要理解函数!

    挑战

    挑战 A:黄金时段

    当我在熟悉一门编程语言的时候,我做的第一件事就是写一个函数来确定一个数字是不是素数。这是你的第一个挑战:
    首先,写下面的函数:

    func isNumberDivisible(number: Int, by byNumber: Int) -> Bool
    

    你会用它来判断一个数字能否被另一个除尽。当 number 可以被 byNumber 除尽的时候应该返回 true。

    提示:你可以使用模除(%)操作符来判断一个数字是不是可以被另一个数字除尽:x % y = 0 的时候 x 可以被 y 除尽。
    接下来,写主函数:

    func isPrime(number: Int) -> Bool
    

    如果一个数字是素数(prime)应该返回 true,否则是 false。一个数字如果只能被 1 和自己除尽,那它就是素数。你应该循环数字,从 1 到 这个数字,寻找它的除数。如果它有任何不适 1 和它自己的除数,那这个数字就不是素数。你会需要使用你之前写的 isNumberDivisible(_:by:) 函数。

    使用这个函数来判断下面的情况:

    isPrime(6) // false
    isPrime(13) // true
    isPrime(8893) // true
    

    提示 1:小于 0 的数字应该被认为不适素数。函数开始的时候检查这个情况,如果数字小于 0 就早点返回。
    提示 2:使用循环来寻找除数。如果从 2 开始到数字自己之前结束,那当你找到一个除数的时候,就可以返回 false。
    提示 3:如果你真的想聪明一点,循环可以只从 2 到 number 的平方根,而不是一路直到 number 自己。把它留作一个给你的练习,搞明白这是为什么。想想数字 16,平方根是 4,会很有帮助。16 的除数是 1,2,4,8 和 16。

    挑战 B:递归函数

    这个挑战里,我们要看看如果一个函数调用自己会发生什么,一个叫做递归(recursion)的行为。这听起来可能不太寻常,但它可以非常实用。
    我们要写一个函数,计算斐波那契数列(Fibonacci sequence)中的一个值。这个数列中的任意值是前两个值的和。数列定义前两个值等于 1。也就是,fibonacci(1) =1 以及 fibonacci(2) = 1。
    使用下面的声明写这个函数:

    func fibonacci(number: Int) -> Int
    

    然后,验证你写的函数是否正确,通过用下面的数字执行它:

    fibonacci(1)  // = 1
    fibonacci(2)  // = 1
    fibonacci(3)  // = 2
    fibonacci(4)  // = 3
    fibonacci(5)  // = 5
    fibonacci(10) // = 55
    

    提示 1:对于小于 0 的 number 值,应该返回 0。
    提示 2:要开始数列,强行让 number 等于 1 或 2 的时候返回值 1。
    提示 3:对于任何其他值,你需要返回用 number - 1 和 number - 2 来调用 fibonacci 的和。

    挑战源代码

    https://yunpan.cn/cBWff6BiWqPbm (提取码:f63a)


    介绍

    欢迎来到Swift世界!Swift是一门苹果在2014年夏天发布的编程语言。从那之后,Swift发布了一个主要的版本跳跃,成为了开始在苹果平台:iOS,OS X,watchOS和tvOS开发的最简单的方式。

    谁适合这篇教程

    这篇教程适合懂一点编程、并且希望学习Swift的人。也许你已经为网站写过一些JavaScript代码,或者用Python写过一些简短的程序。这篇教程就是为你准备的!你会学习到编程的基本概念,同时也会成为Swift语言小能手。

    如果你是赤裸裸的编程新手,这篇教程也是为你准备的!教程里贯穿有简短的锻炼和挑战来给你一些编程练习,同时测试你的知识。

    需要准备什么

    要看这篇教程,你需要准备如下的东西:

    • 一台运行OS X El Captian(10.11)的Mac,带有最新发布的更新并且安装了安全补丁。这样你才能够安装需要的开发工具:最新版本的Xcode。
    • Xcode 7.3 或更新的版本。Xcode是用Swift写代码的主要开发工具。最小也需要Xcode 7.3版本,因为那个版本包含Swift 2.2。你可以免费从Mac App Store下载Xcode的最新版本,这里:http://apple.co/1FLn51R

    如果你还没有安装Xcode最新版本,在继续看下面的教程前要确定安装。

    如何使用这篇教程

    每篇教程都会介绍触手可及的话题理论,伴随大量Swift代码来示范在学习的实际的应用程序。

    教程里的所有代码都是平台中立的;这意味着不是为iOS、OS X或任何其它平台而特定。代码在playgrounds里运行,你在本篇中已经学习了。

    在剩下的教程里,你可以把代码在自己的playground里输入进去。这样你就可以和代码“玩耍”(play around),做一些改变立即就能看见代码运行的结果。

    剩下的教程里会贯穿实际小练习,都是简短的练习,关于触手可及的主题。每篇的末尾也有挑战,会有编程问题也会有长一点的代码练习来测试你的知识。做完就能掌握大部分的Swift基础知识。

    教程更新

    教程会随Swift语言的更新而更新,会发布在我的简书和知乎专栏上,搜索“张嘉夫”即可关注我。

    目录

    本教程从一些基础工作开始来让你起步:

    • 第1篇,编程本质 & Playground基础 - 这就是,到编程世界的入门介绍!你会从电脑和编程的预览开始,然后剩余时间给Swift playground打个招呼。
    • 第2篇,变量 & 常量 - 你会学习到变量和常量,这是用来存储数据的“地方”。你也会学习数据类型以及Swift如何追踪数据类型并在代码中进行传输。
    • 第3篇,数字类型 & 操作 - 你会从基础的数字类型比如整形和浮点型数字开始,当然也包括布尔类型。也会看到一些在实际操作,从比较到算数操作如加减。
    • 第4篇,字符串 - 用字符串来存储文字-从按钮里的文字到图片的标注到这篇教程全部的文字,存储这所有的一切!你会学习到string和character类型,以及基于这些类型的一些常见操作。

    在脑海中有基础数据类型后,就该用那些数据做一些事情了:

    • 第5篇,做判断 - 代码不总是直接从头运行到尾。你会学习在代码里如何做判决并且设定情况来运行某段代码。
    • 第6篇,重复步骤 - 继续不要让代码直线运行的主题,你会学习到如何使用循环来重复某些步骤。
    • 第7篇,函数 - 函数是Swift中用来构建代码的基础建筑。你会学习到如何定义函数来分组代码到可复用单元中。
    • 第8篇,闭包(Closures) - 闭包和函数很接近。你会学习到如何使用它们来轻松传递代码块。

    最后一篇会回到数据:

    • 第9节,可选值 - 这篇讲可选值,Swift中的一种特殊类型,表示既有可能是一个真实的值也有可能没有值。这篇的最后你会知道为什么要用可选值以及如何安全地使用它们。

    这些基础会让你快速开始Swift之路,做好接触更高级编程主题的准备。

    相关文章

      网友评论

        本文标题:一个下午让你掌握Swift基础 ( 7/9 ) 函数

        本文链接:https://www.haomeiwen.com/subject/kehjjttx.html