[翻译]Swift编程语言——函数
函数函数函数就是要完成一个特定任务的一坨代码。你可以以函数的作用给一个函数命名,必要的时候这个名字就可以用来调用这个函数。 定义和调用函数当定义一个函数,你需要定义一个或多个名字和类型,输入(参数)和输出(返回)。 func sayHello(personName:String)->String{ let greeting="Hello,"+personName+"!" return greeting } 所有这一切被包含在了函数定义中,函数定义有前置关键字 func。使用箭头(连字符跟一个右向的尖括号)表明函数的返回类型,紧随其后的就是函数的返回类型。 println(sayHello("Anna")) //prints "Hello,Anna!" println(sayHello("Brian")) //prints "Hello,Brian!" 你调用了sayHello函数通过在圆括号中传递了一个String类型的值(sayHello(”Anna”))。因为这个函数返回一个String类型的值,所以可以被println函数包裹起来打印返回结果。 func sayHelloAgain(personName:String)->Stirng { return "Hello again,“+personName + "!" } println(sayHelloAgain("Anna")) // prints "Hello again,Anna!" 函数的参数和返回值Swift的函数参数以及返回值是非常灵活的。简单到只有一个无名参数的函数,复杂到有命名的参数和不同参数的选项。 多个参数函数可以有多个参数(写在圆括号中用逗号分隔)。 func? ?halfOpenRangeLength?(?start?: ?Int?,?end?: ?Int?) -> ?Int? { ? ?return? ?end? - ?start ?} ?println?(?halfOpenRangeLength?(?1?,?10?)) ?// prints "9" 没有参数函数的参数不是必要的。下面的函数不需要参数,每次被调用都返回同样的String信息: ?func? ?sayHelloWorld?() -> ?String? { ? ?return? ?"hello,world" ?} ?println?(?sayHelloWorld?()) ?// prints "hello,world" 函数定义后面仍然需要跟上圆括号,虽然没有任何参数。调用的时候需要在函数名称后面跟一对空的圆括号。 没有返回值函数的返回值也不是必须的。这里有另外一个版本的sayHello函数叫做sayGoodbye,这个版本只是打印了内容而不是返回了内容: ?func? ?sayGoodbye?(?personName?: ?String?) { ? ?println?(?"Goodbye,?(?personName?)?!"?) ?} ?sayGoodbye?(?"Dave"?) ?// prints "Goodbye,Dave!" 因为这个函数不需要返回值,所以函数定义里面没有包括箭头和返回类型。 在调用时函数的返回值是可以被忽略的: 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" but does not return a value 上例中第一个函数:printAndCount,打印了一个字符串并且将其中的字符个数作为返回值。第二个函数,printWithoutCounting,调用了第一个函数,但是忽略了它的返回值。当第二个函数被调用时,信息会被打印,但是返回值被忽略了。 多个返回值你可以使用元组作为函数的返回值,这样可以将多个值组合起来返回。 func? ?minMax?(?array?: [?Int?]) -> (?min?: ?Int?,?max?: ?Int?) { ? ?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?) minMax函数返回了一个包含两个Int数字的元组。这两个值被分别标签为:min和max,有了标签,就可以对函数的返回值做进一步的访问。 ?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" 记住:上面元组成员不需要被命名当他们作为函数的返回值返回时,因为他们的名字已经在函数的返回值定义中有了。 可选择元组返回类型如果函数返回的元组可能没有值,那么可以使用可选元组作为返回类型,表示返回的元组可能是nil。写法就是在元组后面加问号,像这样:(Int,Int)? 或者 (String,Int,Bool)?。 上面minMax函数返回了一个包含两个Int的元组。但是它没有对输入的参数数组做任何安全检查。如果输入的数组是空的,那么访问它的第一个元素array[0],就会造成运行时错误。 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?) 你可以使用选择绑定判断这个版本的minMax函数的返回值是有效值还是nil: if? ?let? ?bounds? = ?minMax?([?8?,?71?]) { ? ?println?(?"min is ?(?bounds?.?min?)? and max is ?(?bounds?.?max?)?"?) ?} ?// prints "min is -6 and max is 109" 函数参数名称所有上面的函数定义了他们的参数在参数列表中: func? ?someFunction?(?parameterName?: ?Int?) { ? ?// function body goes here,and can use parameterName ? ?// to refer to the argument value for that parameter ?} 然而,这些参数名称只能在函数的函数体内使用,在调用函数时不能使用。这类的参数被称为局部参数名称( local parameter names),因为他们只在函数体内有效。 外部参数名称给参数分别起名字表示参数各自的含义这是件非常有意义 事,在调用函数的时候。 ?func? ?someFunction?(?externalParameterName? ?localParameterName?: ?Int?) { ? ?// function body goes here,and can use localParameterName ? ?// to refer to the argument value for that parameter ?} NOTE 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?: ?",world" 采用了外部参数名称,使得第二个版本的join函数在调用的时候很明晰。 简写外部参数名称如果你要给参数使用外部名称,同时你的局部参数名称就能够表示参数的含义了,这时你不必写两次同样的名称分别表示它们了。写那个名字一次,在它的前面加上井号就可以,这个告诉Swift这个参数的局部名称和外部名称相同。 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" question: 默认的参数值可以在函数定义到时候给参数定义默认值。如果参数有了默认值,调用函数的时候可以将其省略。 func? ?join?(?string? ?s1?: ?String?,? ?withJoiner? ?joiner?: ?String? = ?" "?) -> ?String? { ? ?return? ?s1? + ?joiner? + ?s2 ?} 如果在调用时joiner被传入了一个字符串,这个字符串将和上一个版本中一样将其他两个字符串连接起来: join?(?string?: ?"hello"?,?withJoiner?: ?"-"?) ?// returns "hello-world" 然而,如果没有字符串传给joiner,那么默认值“ ”将会派上用场: join?(?string?: ?"hello"?,?toString?: ?"world"?) ?// returns "hello world" 有默认值的外部参数名称给有外部参数名称的参数提供默认值也是必须的。同样是为了保证函数被调用的时候更便于理解。 ?func? ?join?(?s1?: ?String?,?joiner?: ?String? = ?" "?) -> ?String? { ? ?return? ?s1? + ?joiner? + ?s2 ?} 这个例子中Swift给joiner提供了一个外部参数名称(和局部参数名称一致)。为了让有默认值的参数在调用时目的明确,必须使用它的外部参数名称。 join?(?"hello"?,?joiner?: ?"-"?) ?// returns "hello-world" NOTE 可变参数(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?,?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 不可修改参数和可修改参数函数的参数默认是常量。试图在函数体内修改参数的值,将会返回一个编译时错误。这就意味着你不能修改参数的值。 func? ?alignRight?(?var? ?string?: ?String?,?count?: ?Int?,?pad?: ?Character?) -> ?String? { ? ?let? ?amountToPad? = ?count? - ?countElements?(?string?) ? ?if? ?amountToPad? < ?1? { ? ?return? ?string ? } ? ?let? ?padString? = ?String?(?pad?) ? ?for? ?_? ?in? ?1?...?amountToPad? { ? ?string? = ?padString? + ?string ? } ? ?return? ?string ?} ?let? ?originalString? = ?"hello" ?let? ?paddedString? = ?alignRight?(?originalString?,?10?,?"-"?) ?// paddedString is equal to "-----hello" ?// originalString is still equal to "hello" 这个例子定义了一个新函数叫做alignRight,它的作用是按照一个长度向右对其文本。左侧的空白区域会被一个特殊的填充字符占据。这个例子中,字符串“hello”被转换成了字符串“——hello”。 In-Out参数上述的可修改参数,只能在函数体内被修改。如果你想让一个函数能够修改参数,并且在函数执行完后保持这个修改,那么定义一个in-out参数吧。 func? ?swapTwoInts?(?inout? ?a?: ?Int?,?inout? ?b?: ?Int?) { ? ?let? ?temporaryA? = ?a ? ?a? = ?b ? ?b? = ?temporaryA ?} 这个函数将两个in-out参数的值做了交换。其间使用了常量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" 上面显示someInt和anotherInt的初始值被swapTwoInts函数修改了,尽管这两个变量在函数外定义。 函数类型每个函数都有特定的函数类型,由参数的类型和返回值的类型决定。 func? ?addTwoInts?(?a?: ?Int?,?b?: ?Int?) -> ?Int? { ? ?return? ?a? + ?b ?} ?func? ?multiplyTwoInts?(?a?: ?Int?,?b?: ?Int?) -> ?Int? { ? ?return? ?a? * ?b ?} 这个例子定义了两个简单的数学计算函数,分别叫做addTwoInts和multiplyTwoInts。这个函数有两个Int参数,一个Int类型的返回值(数学计算的结果)。 func? ?printHelloWorld?() { ? ?println?(?"hello,world"?) ?} 这个函数的类型是:() -> (),或者“一个没有参数返回Void的函数类型”。函数没有明确返回值的情况都返回Void,在Swift中其实是返回一个空的元组,显示为()。 使用函数类型函数类型是Swift语言中的另一种类型。举例说明,你可以定义一个函数类型的常量或者变量,然后给其赋值: ?var? ?mathFunction?: (?Int?,?Int?) -> ?Int? = ?addTwoInts 这行代码可以这样解读: println?(?"Result: ?(?mathFunction?(?2?,?3?))?"?) ?// prints "Result: 5" 同理,相同的函数类型函数都可以赋值给那个变量: ?mathFunction? = ?multiplyTwoInts ?println?(?"Result: ?(?mathFunction?(?2?,?3?))?"?) ?// prints "Result: 6" 和其他类型一样,进行赋值时,你可以让Swift自己去猜测常量和变量的类型: let? ?anotherMathFunction? = ?addTwoInts ?// anotherMathFunction is inferred to be of type (Int,Int) -> Int (尽管没有定义anotherMathFunction的类型,但赋值内容已经有了足够多的信息了) 函数类型作为参数你可以把一个函数类型(比如(Int,Int) -> Int)作为另一个函数的参数类型。这样做,在函数被调用时让函数的调用者可以提供函数的具体表现。 ?func? ?printMathResult?(?mathFunction?: (?Int?,?Int?) -> ?Int?,?a?: ?Int?,?b?: ?Int?) { ? ?println?(?"Result: ?(?mathFunction?(?a?,?b?))?"?) ?} ?printMathResult?(?addTwoInts?,?5?) ?// prints "Result: 8" 这个例子定义了一个函数叫做printMathResult 的函数,它有三个参数。第一个参数叫做mathFunction是一个(Int,Int) -> Int的函数类型。你可以传递任何符合该类型的函数作为第一个参数。第二和第三个参数分别被叫做a和b,他们都是Int类型的。他俩作为传入的数学函数的参数使用。 函数作为返回类型你可以使用函数类型作为另一个函数的返回类型。这样做需要在定义函数的时候在->后面书写完整的函数定义。 func? ?stepForward?(?input?: ?Int?) -> ?Int? { ? ?return? ?input? + ?1 ?} ?func? ?stepBackward?(?input?: ?Int?) -> ?Int? { ? ?return? ?input? - ?1 ?} 这里有一个函数叫做chooseStepFunction,它返回一个函数类型:(Int) -> Int。chooseStepFunction 返回函数stepForward 或者stepBackward,依据是一个布尔类型的变量backwards: func? ?chooseStepFunction?(?backwards?: ?Bool?) -> (?Int?) -> ?Int? { ? ?return? ?backwards? ? ?stepBackward? : ?stepForward ?} 现在你可以使用chooseStepFunction 来获得一个(自增或自减的)函数: var? ?currentValue? = ?3 ?let? ?moveNearerToZero? = ?chooseStepFunction?(?currentValue? > ?0?) ?// moveNearerToZero now refers to the stepBackward() function 前述的例子根据变量currentValue 来得到?moveNearerToZero? 常量的值(一个正向或负向改变值趋于0的函数)。 println?(?"Counting to zero:"?) ?// Counting to zero: ?while? ?currentValue? != ?0? { ? ?println?(?"?(?currentValue?)?... "?) ? ?currentValue? = ?moveNearerToZero?(?currentValue?) ?} ?println?(?"zero!"?) ?// 3... ?// 2... ?// 1... ?// zero! 嵌套函数本章中你遇到的所有函数都是全局函数(global 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! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |