Swift中函数的灵活应用

前言

 Swift中函数的使用是非常灵活的,比如,函数有自己的类型,可以当作参数、返回值,还有Swift中还引入了函数式编程。

一、函数类型

1、什么是函数类型

每个函数都有特定的函数类型,函数类型是有函数的参数和返回值共同组成的。
(1) func addTwoInts(a:Int,_b:Int)->Int{ return a+b } (2) fun printHelloWorld(){ } (3) fun mathFunction()->Int{ }
上面三个函数的类型分别是(Int,Int)->Int,()->void,()->Int
在Swift中我们可以把函数类型像其他的类型一样使用,比如我们可以把函数类型声明成var,let,可以把函数类型当作参数,当作返回值等。
func addTwolints(a:Int,b:Int)->Int{ return a+b } func subtractionFuction(a:Int,b:Int)->Int{ return a - b } let addFuction:(Int,Int)->Int = addTwolints var subFuction:(Int,Int)->Int = subtractionFuction subsection = addFuction//类型一样的才能这么赋值 let result:Int = subsection(5,5)

2、函数类型怎么使用范围

函数类型可以做常量、变量参数、返回值,下面有几个小例子可以很好的说明

(1)、函数类型做常量和变量

func addTwolints(a:Int,b:Int)->Int{ return a+b } func subtractionFuction(a:Int,b:Int)->Int{ return a - b } let addFuction:(Int,Int)->Int = addTwolints//定义一个(Int,Int)->Int类型的常量addFuction var subFuction:(Int,Int)->Int = subtractionFuction subsection = addFuction//类型一样的才能这么赋值 let result:Int = subsection(5,5)

(2)、函数类型做参数

函数有三个参数有一个(Int,Int)->Int类型的mathFunction,和两个Int类型
\* printMathResult()函数有三个参数 *\ func printMathResult(mathFunction:(Int,Int)->Int,a:Int,b:Int){ print("Result:\(math)") } printMathResult(addTwolints,3,5)

(3)、函数类型做返回值

同样贴出官方给出的例子
fun setpForward(a:Int)->Int{ return a + 1 } func setpBackward(b:Int)->Int{ return b - 1 } func chooseStepFuction(backwards:Bool)->(Int)->Int{ return backwards ? setpForward: setpBackward }

二、闭包

感觉Swift中的函数也很简单明了,好吧,这儿有两个字符串看看他们是什么?怎么会有这么奇葩的写法
(a)、var myLowerString:String = { "myLowerString" }() (b)、 var myMaxString:String{ return "myMaxString" }
看上去是不是不好明白,其实上面两个是一样的他们都是使用Swift中的闭包给字符串赋值,只是写法进化了,现在我们一步一步的让它退化
(1)、上面a式可以退化成这样:
var myLowerString:String = { return "myLowerString" }()
只是多了个return还是不好明白
再次退化可以写成这样:
var myLowerString2:String = { () in return "myLowerString" }()
目前这个样子是不是已经很接近Closures的标准写法了,换一个式子加两个参数就是标准写法:
var myLowerString3:String = { (s1,s2) in return s1 + s2 }("hello","world")
补上两个参数(a)式终于露出了本来面目,上面的(b)式经过这样一步退化就会变成(a)式:
var myMaxString:String={ return "myMaxString" }()
好吧,如果我把Closures认为也是函数的一种特殊形式,或者反之那么Swift中函数的灵活度我已经无力吐槽了,其实这只是刚刚开始下面函数式编程会使其更加灵活。

1、Closures的表达式

上面举了个闭包的例子,现在照着官方文档一步步学习,闭包是自包含代码块,可以在代码中传递和使用(如果认为它是函数这个也很好理解),当然在Objective-C中我们把这种写法称为blocks(代码块)。官方文档说闭包有三种形式:
(a)、全局函数:全局函数是一个有名字但不会捕获任何值的闭包
(b)、嵌套函数:是一个有名字并可以捕捉起封闭函数域内值的闭包
(c)、闭包表达式:闭包表达式是一个利用轻量级语法缩写的可以捕获其上下文变量或常量的匿名闭包

(1)、全局函数和嵌套函数

对于全局函数和嵌套函数官方文档是这么说的:
All of the functions you have encountered so far in this chapter have been examples of global functions, which are defined at a global scope. You can also define functions inside the bodies of other functions, known as nested functions.虽然没有找出明确的说明但是我觉得函数就是闭包?
这儿贴出两个函数作为参考:
func sayHello(personName: String) -> String { let greeting = "Hello, " + personName + "!" return greeting }//这个全局函数 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 }// 这个嵌套函数理解起来很容易

(2)、捕获值(Capturing Values)

在全局函数和嵌套函数中有出现了一个词“捕获值(Capturing Values)”,官方解释是这样的:闭包可以在其被定义的上下文中捕获常量或变量。即使定义这些常量和变量的原作用域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值,大致意思也就是说闭包可以在它被定义的上下文中捕捉和持有变量和常量。官方使用嵌套函数很好解释了这个概念
func makeIncrementor(forIncrement amount: Int) -> () -> Int { var runningTotal = 0 func incrementor() -> Int { runningTotal += amount return runningTotal } return incrementor }
makeIncrementor函数需要输入Int类型的参数amount,返回一个 () -> Int类型的函数,里面定义个一个可变的runningTotal,嵌套了一个incrementor函数,不需要参数,返回Int类型。我们可以看到内嵌函数incrementor拷贝并持有了一份amount,引用并持有了runningTotal。这样闭包持有的值占用的内存在什么时候释放,就有闭包去管理了。(说到这儿插入一句题外话,由于闭包的这个(捕获值)特性,闭包中如果出现self,self就会被闭包持有,如果实例直接或者间接的引用闭包就会造成一个”完美的环“,self->闭包->self,这样循环引用就悄无声息的形成了)执行下面的代码:
let incrementByTen = makeIncrementor(forIncrement: 10) print(incrementByTen())//10 print(incrementByTen())//20 print(incrementByTen())//30

(3)、闭包表达式

现在终于轮到主角闭包表达式登场了,闭包表达式:闭包表达式是一种利用简洁语法构建内联闭包的方式官方说他们对Swift的闭包进行了下列优化
(a)、利用上下文推断参数和返回值类型 (b)、隐式返回单表达式闭包,即单表达式闭包可以省略return关键字 (c)、参数名称缩写 (d)、尾随(Trailing)闭包语法
上面这些就是闭包写法进化的依据。再用官方的例子吧,毕竟我是写不出也想不出比官方给的例子更能表达问题的例子了。
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"] func backwards(s1: String, s2: String) -> Bool { return s1 > s2 } var reversed = names.sort(backwards)// reversed 为 ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
sort函数可以根据传入的排序函数对数组进行排序,并返回重新排序的数组。
如果传入闭包就应该是这样首先贴出闭包语法的一般形式:
{ (parameters) -> returnType in statements }
var reversed = names.sort({ (s1: String, s2: String) -> Bool in return s1 > s2 })
这么写跟上面写有什么却别?其实没有区别,只不过是把有名字的闭包(backwards)换成没名字的闭包(闭包表达式)
上面说了闭包表达式有上下文推断功能(Inferring Type From Context),那么由于names是字符串类型的数组,所有s1,s2类型应该可以推断出来上面的闭包表达式就可以开始进化成这样:
var reversed = names.sort( { s1, s2 in return s1 > s2 } )
单表达式隐式返回(Implicit Return From Single-Expression Clossures)又是怎么回事?
简单的说就是如果in后面的表达式只有return这一行,那么就可以省略掉return就像下面这样
reversed = names.sort( { s1, s2 in s1 > s2 } )
参数名缩写(Shorthand Argument Names)这个技能,所谓参数名缩写就是把闭包中的参数名省掉,而是用$0,$1,$2有序的替代参数。这样说的话,上面的式子可以接着简写成这样:
reversed = names.sort( { $0 > $1 } )
如果你觉得这样还不够简练那我们还可以接着简写只保留一个运算符号,干脆参数都不要了:
reversed = names.sort(>)
所有技能都用上进化成这种程度已经算是终极进化了吧。

4、尾随闭包(Trailing Closures)

尾随闭包需要一个条件:闭包作为最后一个参数,同时尾随闭包体现在函数的调用上.
下面的例子就是使用尾随闭包的对比:
``

   func someFunctionThatTakesAClosure(closure: () -> Void) {
        // 函数体部分
        print("someFunctionThatTakesAClosure")
    }
   //不使用函数闭包进行函数调用
    someFunctionThatTakesAClosure { () -> Void in
       //闭包主体部分
   }
  //使用函数闭包进行函数调用
    someFunctionThatTakesAClosure(){
     //闭包主体部分
    }

如果使用上面sort函数进行句例子,那么sort函数应该是这样的
reversed = names.sort(){>}
官方又说了,如果这个函数的参数只有这么一个闭包的话那么有可以这样简写:
reversed = names.sort{>}
写到这儿我不得不吐槽了,搞这么灵活是故意折麽我们程序员吗?是不是有点怀念Object-C了? 为了安慰我们官方有举了个例子,告诉我们这么写的好处:

     let digitNames = [
      0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",
      5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
    ]
    let numbers = [16, 58, 510]
    
    let strings = numbers.map {
        (var number) -> String in
        var output = ""
        while number > 0 {
            output = digitNames[number % 10]! + output
            number /= 10
        }
        return output
    }
    print(strings)

上面的map函数是这样的,map方法获取一个闭包表达式作为唯一参数,闭包函数会对数组中的元素每个调用一次,并且返回该元素所映射的值,拘役的映射方法和返回值类型,由闭包决定,说白了,也就是,闭包方法处理数组中的每一个值,并返回处理后的结果,numbers经过[%10] = [6,8,0],对应的字符串是:Six,Eight,Zero,经过number /= 10处理 = [1,5,51]对应的字符串是One,Five,OneZero,所以strings = ["OneSix", "FiveEight", "FiveOneZero"]

5、非逃逸闭包(Nonescaping Closures)

6、自动闭包(Autoclosures)

三、Swift中的函数式编程

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

推荐阅读更多精彩内容