苹果新的编程语言 Swift 语言进阶(六)--函数和闭包
一 、函数
1.1、 函数的定义和调用
函数的定义以funckeyword作为前缀,接着是函数名字,接着跟着一个能够带有參数。也能够不带參数的圆括号。接着用-> 指示函数的返回类型。
函数运行体用一对大括号{}包围。例如以下定义了一个函数名为sayHello的函数。该函数包括一个名字为personName,类型为String的输入參数。
func sayHello(personName:String)
-> String {let greeting
="Hello, " +personName +"!"return greeting
}
你能使用上面定义的函数名sayHello并在圆括号里包括一个传给该函数的一个字符串參数值来调用该函数。
比如
sayHello(“Anna”)。
Swift也能够定义一个不带返回值的函数,如
func sayGoodbye(personName:String)
{println("Goodbye,\(personName)!")
}
注: 未定义返回值函数的返回类型为Void,是一个空的多元组(包括零个元素),写作()。
Swift中能够使用一个多元组类型作为函数的返回类型,以便从一个函数返回多个值。
func count(string:String)
-> (vowels:Int,consonants:Int,others:Int)
{return (vowels,consonants,others)
}
以上定义的函数中的參数在圆括号里以parameterName:parameterType形式定义,以这样的形式定义的參数称为本地參数,即仅仅能在函数运行体内部使用,不能在函数调用时使用。
Swift支持为一个函数的每个參数命名一个外部參数。外部參数在函数本地參数的前面声明。例如以下所看到的:
func join(string s1:String,toString s2:String,withJoiner joiner:String)
->String {
return s1
+joiner +s2}
为一个函数命名的外部參数能够在也仅仅能在函数调用时使用。
例如以下所看到的在调用上面的函数时加上以上为參数命名的外部參数名字。
join(string:"hello",toString:"world",withJoiner:",
“)
为函数參数命名一个外部參数主要是为了使函数的參数意义更加清晰。
假设一个函数的本地參数名字已经比較适当。这时能够在函数的本地參数名字前加上一个’#’符号。指示该參数名字即用作本地參数名,又用于外部參数名。
如:
func containsCharacter(#string:String,
#characterToFind:Character) ->Bool
{}
Swift中,你还能在函数定义中为函数的随意參数定义一个默认值。假设为一个函数的某个參数提供了默认值。在调用该函数时就行不传送定义默认值的參数。
定义默认值的參数要放到函数參数列表的末端,未定义默认值的參数要放到函数參数列表的前面,以便调用函数的形式统一。
fund join(string s1:String,toString s2:String,
withJoiner joiner:String
=" ") ->String {return s1
+joiner +s2}
以上join函数为joiner參数定义了默认參数。因此能够用例如以下方式调用该函数,第三个參数没有被传递,函数内部使用其默认值:
join(string:"hello",toString:"world")
// returns "hello world”
多数情况下为带默认值的參数提供一个外部名字是必要和实用的。这样可以在调用该函数时使函数表达的功能更加清晰。
因此针对这样的情况,假设不为默认參数提供一个外部名字。Swift自己主动为其分配一个外部參数名。自己主动分配的外部參数名与其本地名字同样。例如以下样例:
func join(s1:String,s2:String,joiner:String
=" ") ->String {return s1
+joiner +s2}
如上函数Swift自己主动为带默认值的joiner參数提供了一个外部參数名,其名字和其本地名字joiner同样。
因此调用该函数时必须为其提供外部名字,从而使函数參数的表达的意思更加清楚和没有歧义。
join("hello","world",joiner:“-")
Swift 也支持函数带有可变參数。用来接受零个或多个特定类型的參数。可变參数在參数类型后面加...符号标识。传给函数的可变參数在函数体内作为一个适当类型的数组使用。
例如以下样例展示了一个使用可变參数的函数样例。
func arithmeticMean(numbers:Double...)
-> Double {var total:Double
=0for number in numbers
{total +=number
}
return total
/Double(numbers.count)}
为了避免歧义,函数的可变參数总是出如今函数參数列表的最后。
函数參数默认是常量类型,不须要加let 标识。但 Swift 支持在函数定义中使用varkeyword定义变量參数,变量參数也仅仅在函数运行体内部有效和使用。
func alignRight(var string:String,count:Int,pad:Character)
->String {let amountToPad
=count -countElements(string)for _ in 1 ... amountToPad
{string =pad
+string}
return string
}
Swift 为了支持一个函数体内部对參数改动的值仍可以在函数调用结束后被外部所用。定义了一种in-out 參数。
Swift在參数定义的前面加入一个inoutkeyword来定义一个in-out 參数。in-out 參数能够在函数内部改动传进来的值。并传回取代原先的值。因为in-out 參数作为一个变量使用。因此在调用函数时须要在其名字前面须要放一个&标记符来指示该參数是一个函数内部能够改动并传回值的in-out
參数。
须要注意的是in-out 參数不能没有默认值,可变參数也不能标记为inout參数,也不能使用var或letkeyword来标记它。
func swapTwoInts(inout a:Int,inout b:Int)
{let temporaryA
=aa =b
b =temporaryA
}
以上swapTwoInts函数定义了两个inout參数,用来在函数内部实现两个參数值的交换。
能够使用例如以下方式调用该函数:
var someInt =3
var anotherInt =107
swapTwoInts(&someInt, &anotherInt)
1.2、 函数类型及使用
每一个函数都属于一种特定的函数类型,函数类型由參数类型和函数的返回类型组成。
func addTwoInts(a:Int,b:Int)
->Int {return a
+b}
func multiplyTwoInts(a:Int,b:Int)
->Int {return a
*b}
比如以上定义的两个函数属于同样的函数类型。其类型为:(Int, Int) -> Int。
在Swift中能够像其他类型一样使用函数类型(函数类型是一种引用类型),如定义一个常量或变量是一个函数类型并为其分配一个适当的函数。
let anotherMathFunction
=addTwoInts
// anotherMathFunction 被判断为是一个(Int, Int) -> Int函数类型。
你也可以使用函数类型作为另外函数的參数。例如以下所看到的:
func printMathResult(mathFunction: (Int,Int)
->Int, a:Int, b:Int)
{println("Result:\(mathFunction(a,b))")
}
printMathResult(addTwoInts,3,5)
也可以使用函数类型作为另外函数的返回类型,如:
func stepForward(input:Int)
->Int {return input
+1}
func stepBackward(input:Int)
->Int {return input
-1}
以上定义了具有同样类型的两个函数。
func chooseStepFunction(backwards:Bool)
-> (Int) ->Int {return backwards
?stepBackward :stepForward
}
// 该函数依据參数的不同值返回不同的函数。
var currentValue =3
let moveNearerToZero =chooseStepFunction(currentValue
>0)
currentValue =moveNearerToZero(currentValue)
1.3、函数的嵌套
在Swift中。能够在函数运行体内定义其他函数。被称为函数嵌套,一个函数内部定义的函数称为嵌套函数,最外面定义的函数统称为全局函数。嵌套函数默认对外部隐藏。仅能在定义它的函数内部调用或使用。但包括一个嵌套函数的函数能够返回它所包括的嵌套函数以便嵌套函数能够被外部使用。例如以下所看到的:
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}
以上函数chooseStepFunction内部定义了两个内嵌函数。并依据传进的參数值返回两个内嵌函数之中的一个。
二 闭包(Closures)
2.1 闭包定义
闭包是一个自包括的功能块,能像函数一样使用,闭包类似于C 和 Objective-C语言中定义的块(blocks)。
像函数一样闭包也是一种类型(引用类型)。也能分配一个闭包到一个常量或变量,实际上该常量或变量指向该闭包的一个引用。
全局函数和嵌套函数是闭包的特例。Swift中闭包指的是例如以下三种形式之中的一个:
1) 全局函数,全局函数不可以捕获不论什么值。
2) 嵌套函数,嵌套函数能从定义它们的函数中捕获值;
3) 闭包表达式是没有名字的闭包,是实现闭包的轻量级语法形式,闭包表达式能从它们的使用上下文中捕获值。
闭包表达式的语法形式为:
{ (parameters) -> return type in
statements
}
闭包表达式与函数的主要不同是闭包表达式没有函数名。整个闭包表达式的内容用一对大括号包含,闭包表达式的參数和返回类型也在大括号内部声明,并inkeyword来引出闭包表达式的运行体。
闭包表达式像函数一样也能使用常量參数、变量參数或inout參数,也能够使用可变參数。但不同的地方是不能给闭包表达式的參数提供默认值。
例如以下是inline方式使用闭包表达式的一个样例。
reversed = sort(names, { (s1:String, s2:String)
-> Bool in return s1 > s2 } )
2.2 闭包表达式的优化
当以inline闭包表达式传送一个闭包给一个函数时。闭包表达式的參数和类型能够从函数的參数中加以判断,如
上面的sorting闭包作为sort函数的第二个參数传递和使用,Swift能从sort函数的第二个參数的类型来判断该闭包的的參数类型和返回类型为(String, String) -> Bool类型。
因此对于这样的情况,闭包表达式的參数和返回类型在实际代码中非常少须要声明,能够简化为例如以下形式:
reversed =sort(names,
{s1,s2 in return s1
>s2 } )
Swift中,单表达式的闭包可以隐含返回该表达式的运算结果。因此上面的returnkeyword也可以省略。
reversed = sort(names, { s1, s2 in s1 > s2 } )
Swift能够自己主动为inline闭包表达式的參数提供速记名,使用$0,$1,$2等形式来定义和引用闭包表达式包括的參数值。
这时inline闭包表达式的參数列表也能够取消。这时闭包表达式就仅仅包括一个运行体,因此inkeyword也能够省掉。
这样上面使用inline闭包表达式的sort函数能够被优化为例如以下最简化形式:
reversed =sort(names,
{$0 >$1 } )
因为字符串类型实现了一个 >操作符(大于)的字符串操作函数。
该操作函数的函数类型与sort函数的第二个參数须要的函数类型相匹配,因此你能在上面的函数中简单传送一个>操作符。Swift将会帮你判断你想使用它的字符串实现。因此上面的表达式还能够写作例如以下形式:
reversed =sort(names,
>)
假设传送一个闭包表达式作为一个函数的最后一个參数。而且闭包表达式太长。
这时还能够使用闭包推后形式。
闭包推后指的是闭包表达式在调用函数时被写在它支持的函数的參数括号外面。
因此如上的对sort函数调用时能够写成以下的形式,这样使代码的可读性更强。
reversed = sort(names) { $0 > $1 }
假设一个闭包表达式是一个函数的唯一參数,并以闭包推后的形式表达,这时调用函数时函数包括的參数()能够被省去。例如以下样例所看到的:
let strings =numbers.map
{(var number)
->String invar output
=""while number
>0 {output =digitNames[number
%10]! +outputnumber /=10
}
return output
}
2.3 值的捕获
闭包能从定义它们的上下文中捕获引用并赋值给随意的常量或变量。
闭包能够从它被定义的上下文捕获常量或变量,然后在它的运行体内引用或改动捕获的常量或变量。即使定义常量或变量已经不再有效。
如嵌套函数能从定义它的外部函数的參数和外部函数中捕获參数、随意常量或变量等。
func makeIncrementor(forIncrement amount:Int)
-> () ->Int {var runningTotal
=0func incrementor()
->Int {runningTotal +=amount
return runningTotal
}
return incrementor
}
以上样例。makeIncrementor的内嵌函数incrementor从它的定义函数makeIncrementor中捕获了一个变量和一个參数。
因为捕获的參数在内嵌函数运行体内不被改动,因此以原先值的拷贝形式捕获。而捕获的变量须要在内嵌函数运行体内改动,因此这时内嵌函数捕获的是原先变量的一个引用,捕获一个引用确保在定义内嵌函数的外部函数调用结束后,引用仍可以继续有效,而这些都是由Swift自己主动处理的,用户不须要不论什么操作。
例如以下样例所看到的每次对内嵌函数的调用,引用值在原先的基础上改动。尽管外部函数makeIncrementor调用已经结束。
let incrementByTen = makeIncrementor(forIncrement:10)
incrementByTen()
// returns a value of 10
incrementByTen()
// returns a value of 20
incrementByTen()
// returns a value of 30
版权全部,转载时请清楚注明链接和出处,谢谢!
苹果新的编程语言 Swift 语言进阶(六)--函数和闭包的更多相关文章
- 苹果新的编程语言 Swift 语言进阶(十六)--泛型
泛型允许你定义一个宽松.可重用的函数或者类型,使用泛型能够避免代码的重复,也能以更清楚和抽象的方式来表达程序的意图. 泛型是Swift语言提供的强大功能之一,Swift提供的许多标准库都使用了泛型来创 ...
- 苹果新的编程语言 Swift 语言进阶(一)--综述
Swift 是苹果开发和提供的供开发IOS 和OS X应用的一门新的语言.Swift语言基于C 和Objective-C语言,除了提供C 和Objective-C语言具有的所有语法功能外,为了编程方便 ...
- 苹果新的编程语言 Swift 语言进阶(三)--基本运算和扩展运算
一 基本操作运算 1. 赋值操作 在Swift 中,能够使用赋值操作为一个常量或一个变量赋值,也能够使用多元组一次为多个常量或变量赋值. Swift 的赋值操作与其他语言最大的不同是赋值操作除了可以为 ...
- 苹果新的编程语言 Swift 语言进阶(十五)--协议
协议定义了适合某个特定任务或功能需要的方法.属性和其它需求的一个蓝图.协议本身不提供这些需求的实现,它只是描述了一个任务或功能实现的蓝图. 协议与java 语言中的接口定义类似,都是描述了一个实现可以 ...
- 苹果新的编程语言 Swift 语言进阶(十四)--扩展
扩展是为一个已经存在的类.结构.枚举类型添加新功能的一种方式,包括为不能存取源代码的那些已经存在的类型添加功能. 扩展类似于Objective-C语言中的类别,与类别不同的是Swift语言的扩展没有名 ...
- 苹果新的编程语言 Swift 语言进阶(七)--枚举、结构、类
Swift语言中,具有类特征的类型包括三种,即枚举类型.结构类型(包括基本类型,基本类型实际都是结构类型的特例).类.其中枚举类型.结构类型是属于值类型,类属于引用类型.三种类型都可以添加属性.方法. ...
- 苹果新的编程语言 Swift 语言进阶(四)--字符串和收集类型
一.字符串( String )和字符类型(Character) 字符串是一种字符的带次序的收集类型(相当于数组),字符是字符串中的元素. 在Swift 语言中,字符串是编码独立的Unicode字符的 ...
- 苹果新的编程语言 Swift 语言进阶(二)--基本数据类型
一 . 常量和变量 Swift语言 对常量和变量的声明进行了明确的区分 Swift语言的常量类型比C 语言的constants类型更加强大,语义更加明确. 常量和变量的区别是常量在设置或初始化后 ...
- 苹果新的编程语言 Swift 语言进阶(五)--控制流
Swift 语言支持C语言全部的控制语句.包含for 和while循环语句,if和switch条件语句,以及break和continue控制语句等. Swift 语言除了支持以上语句,还添加了一个f ...
随机推荐
- poj 2723 Get Luffy Out 二分+2-sat
题目链接 给n个钥匙对, 每个钥匙对里有两个钥匙, 并且只能选择一个. 有m扇门, 每个门上有两个锁, 只要打开其中一个就可以通往下一扇门. 问你最多可以打开多少个门. 对于每个钥匙对, 如果选择了其 ...
- 【Linux指令】使用中学习(一)
sed指令: 应用:对于大文件,比如10G的大文件,我遇到的是导出的数据库.sql文件,想要使用vim修改几乎是不可能的,用sed指令可以在不打开文件的情况下修改文件,下面是一些具体用法 删除文件特定 ...
- JSP中的Attribute和InitParameter
属性:Attribute类型:应用/上下文,请求,会话(ServletContext,HttpServletRequest/ServletRequest,HttpSession)设置方法:setAtt ...
- 使用MIDAS访问远程Access数据库
使用MIDAS访问远程Access数据库 Allen Tao(http://blog.csdn.net/allentao/) 2005-5-3 本文源码下载 访问远程数据库常用的办法是 ...
- 单机Oracle+asm(11.2.0.3.0) Patch Set Update(11.2.0.3.7 )
之前写过一篇关于PSU升级的案例,参考如下: http://blog.csdn.net/jyjxs/article/details/8983880 但是,感觉有些地方理解的不是很透彻明白,照猫画虎的比 ...
- JavaMail学习笔记
适逢计算机网络课程设计,本着挑战自己的态度,选择了一个从未接触的东西:邮箱客户端代理软件的设计.由于对相关协议非常陌生,只能依靠查找资料完成,在学习过程中碰到了一个非常好的博客,故向大家推荐一下. 一 ...
- 【Linux学习】Ubuntu下嵌入式交叉编译环境arm-linux-gcc搭建
(1)首先选择一个路径用来存放arm-linux-gcc.我选用的是/home/book,并在以下建立一个目录arm-linux-gcc. (2)利用cp EABI-4.3.3_Emdedsky_20 ...
- iOS UISearchBar学习笔记
UISearchBar 是一个搜索控件,它提供了一个文本输入框,一个查找button,一个书签button.一个取消button.我们须要使用UISearchBarDelegate代理来进行查找工作. ...
- VBA 开发学习--基础语法
MsgBox "开始学习VBA" '提示框 Dim str As String '声明str变量是string类型 Let str = "一起来看流星雨" '给 ...
- if---(switch-case)语句初步学习总结
Daily sentence: Happiness is about having each tiny wish come true. 幸福就是达成每一个Tiny Wish. Ctrl+E D C# ...