★ 学习笔记:《iOS高级:Swift入门精讲②》第一节 Swift编程-01➡11 函数类型

前言:

本篇仅为视频学习笔记

函数类型 (Function Type)

★每一个函数都是有类型的,函数类型有形式参数类型、返回值类型组成

例子 -1

func test() { } // () -> Void 或者() -> ()

我们看上边这个函数,其实它的类型就是() -> Void,其中()是参数列表 Void它是返回值,由于它没有参数,所以写成(),返回值写一个Void。Void等价于(),所以函数的类型也可以写成() -> ()。综上,函数的类型可以写成() -> Void或者() -> ()。


我们再看下一个。

例子 -2

 func sum(a: Int, b: Int) -> Int {
     return a + b
 } // (Int,Int)-> Int

它的函数类型是什么呢?是 (Int,Int)-> Int。这样一看,就会明白,它呢,接收了两个Int类型的参数,返回值类型为Int类型


我们再看下一个。

例子 -3

 // 定义变量
 var fn: (Int,Int) -> Int = sum
 fn(2,3) // 5,调用时不需要参数标签

我们可以定义变量,定义一个fn变量,那么这个变量的类型是一个函数类型,既然你这个变量是(Int,Int) -> Int类型,我们就可以赋值一个函数名给fn。当然你赋值的函数名必须符合这个类型。假如呢,你把例子1中的test赋值给fn的话,那肯定会报错。因为sum刚好是这种类型的,所以sum这个函数名可以赋值给fn。那么赋值之后呢,我们就可以利用这个变量去调用这个函数。一调用,就把2和3传递给例2中的a和b了。到时候,就会执行函数sum,内部函数体代码。

像利用变量去调用一个函数的话,那么参数标签是不需要写的。相当于以前,你调用sum将函数的时候,是要写a和b这两个标签的。但是一旦传给一个变量,你就直接写2和3,它会按顺序传递给他们(a和b)。

函数类型作为函数参数

 func sum(v1: Int, v2: Int) -> Int {
     return v1 + v2
 }
 
 func difference(v1: Int, v2: Int) -> Int {
      return v1 - v2
 }
 
 func printResult(_ mathFn:(Int,Int) -> Int, _ a: Int, _ b: Int) {
     print("Result: \(mathFn(a,b))")
 }
 
 printResult(sum, 5, 2) // Result: 7
 printResult(difference, 5, 2) // Result: 3

我们来看一个问题,我们定义了两个函数,一个是做加法的,一个是减法的,然后我们又定义了一个函数printResult来打印结果。函数printResult接收了三个参数,而且这三个参数都写了下划线,那么调用的时候,就不用写标签了。

第一个参数是函数类型,说白了第一个参数要求你传一个(Int,Int) -> Int这种类型的函数,然后第二个、第三个参数传Int。那你思考一下,我们是不是可以这样传呢?

 printResult(sum, 5, 2) // Result: 7
 printResult(difference, 5, 2) // Result: 3

因为我们这个sum函数跟difference这两个函数是不是就是(Int,Int) -> Int这种类型的。所以呢,可以这样传。

那么,传递进去,我会怎么做呢?我会把你传进来的这个函数调用一下,把a和b传到mathFn(a,b)这个函数里。说白了,如果我传的是这个 printResult(sum, 5, 2) ,那么就是把5和2传到了sum函数里去调用。printResult(difference, 5, 2)这个是将5和2传递到difference函数里去调用。并且把这个结果,利用这个斜线小括号放到字符串中打印出来,所以最后打印出来printResult(sum, 5, 2)结果是Result: 7。 printResult(difference, 5, 2)结果是Result: 3。甚至以后,将函数变成一个属性。

甚至以后,将函数变成一个属性。你看下面代码:


以后我们在写一个类的时候,这个类的属性,也就是大家所认为的成员变量,是不是可以有Int类型,也可以有函数类型。到时候可以将一个函数赋值给它。

函数类型作为函数返回值

当然,既然是类型也可以作为函数的返回值类型。比如说举个例子如下:

 func next(_ input: Int) -> Int {
    return input + 1
 }
 
 func previous(_ input: Int) -> Int {
     return input - 1
 }
 
 func forward(_ forward: Bool) -> (Int) -> Int {
     return forward ? next : previous
 }
 
 forward(true)(3)  // 4
 forward(false)(3) // 2

我这个next函数,是你传一个东西给我,我就往前走就是加1。previous函数就是你传一个东西给我,我就往后走减1。这样说吧,next是上一步,previous是下一步。上一步就加1,下一步就减1。

因为函数体,就一个表达式,可以不用写return这个家伙。不写的时候,相当于直接return这个家伙。

forward函数,是你传一个Bool布尔类型给我,我来决定返回哪一个函数给你。你会发现forward函数的返回值是一个函数** (Int) -> Int**。这里千万不要搞晕了。

首先,这一个这一个符号,是 forward函数的返回值的开头,右边那个就是返回值类型,说白了,它返回的是一个函数。然后,这个函数要求接收一个Int类型参数,返回一个Int类型。

很明显 next函数和previous函数都是符合条件的。它们都是接收一个Int,返回一个Int。所以注意看,forward函数中,你传递一个布尔类型Bool给我,我发现这个布尔类型Bool是true,我就返回next函数,否则返回previous这个函数。


所以呢,大家注意看一个问题。到时候,我调用forward这个函数的时候,如果你传一个true进来,我返回的是next函数。所以这个next函数一调用,传一个3的话,就会赋值给next函数中input这个标签,去执行函数体代码。所以3+1 = 4

传一个false,就会返回previous函数,将3传给previous函数中的input这个标签,去执行函数内部代码,其实就是 3 -1,结果为2。


再说一个概念
★ 返回值是函数类型的函数,叫做高阶函数(Higher-Order Function)

typealias

来看一个关键字,typealias这个关键词是什么意思呢?alias是起别名的意思。type是类型,说白了他是给类型,起别名的。

★ typealias用来给类型起别名

那么怎么起别名呢?

 typealias Byte = Int8
 typealias Short = Int16
 typealias Long = Int64

其实我们Swift里面是没有Byte、Short、Long这三个类型的,但是我们可以自己给它们创造一下。

我们思考一下, Byte不就代表一个字节吗?8位。我们可以来一个Int8,Int8不就是代表一个8位的Int类型吗?这样做就可以了。这样就给Int8起了一个别名,叫做Byte。我觉得这个也很好理解,就像将右边Int8赋值给了左边Byte,说白了Byte就等价于Int8。

Short不就是代表两个字节的Int类型吗?我们可以直接将Int16赋值给它(Short)。Long一般代表8个字节,也就是64位的,所以我们将Int64赋值给它(Long)。那么这样,就相当于,我们创造了三个类型吗?


这个起别名,我们给元祖也是可以的。

 typealias Date = (year: Int, momth: Int, day: Int)
 
 func test(_ date: Date) {
     print(date.0)
     print(date.year)
 }
 test((2011,9,10))

我们⚠️注意观察,我现在是给元祖取了一个别名,我们将右边的元祖类型(year: Int, momth: Int, day: Int)赋值给了左边的 Date,所以以后用这个 Date就代表了右边的元祖类型 (year: Int, momth: Int, day: Int)

所以,你注意看 test 函数是接收一个元祖类型 Date,到时候,你思考一下,到时候是不是可以传这个元祖test((2011,9,10))啊。(2011,9,10)中2011、9、10,很明显就是 (year: Int, momth: Int, day: Int)这三个东西。

我将元祖(2011,9,10)传进test函数去了,赋值给了date。拿到元祖,执行函数体代码,我们用点0就date.0可以,访问最前面的成员。也可以通过这个名称year标签,访问到最前面的成员。


然后,我们还可以怎么样呢?给函数类型起一个别名。

总之,你右边能放什么东西呢?类型就行。你可以将右边的类型赋值给左边。既然是放类型,函数类型也是一种类型。如下:

 typealias IntFn  = (Int,Int) -> Int
 
 func difference(v1: Int, v2: Int) -> Int {
      return v1 - v2
 }
 
 let fn: IntFn = difference
 fn(20,10) // 10
 
 func setFn(_ fn: IntFn) {
     setFn(difference)
 }
 
 func getFn() -> IntFn {
     return difference
 }

所以, typealias IntFn = (Int,Int) -> Int 这样写是什么意思呢?你可以用IntFn代表(Int,Int) -> Int 这种函数类型。

那你思考一下,很明显这个 difference函数,就是符合IntFn这种类型的,也就是说白了difference就是符合IntFn这种类型的。

所以,到时候我可以,定义一个IntFn类型的常量fn,然后来存储difference值。这样调用是成功的 fn(20,10) // 10。

到时候,传参也是一样的,我们看setFn函数,要求你传进来的类型是IntFn,那明显difference是符合这个类型的。所以,可以这样传进去 setFn(difference)。

然后,返回值也是一样的。我们getFn,要求返回IntFn类型,所以我这个difference是符合这个类型的,继而返回difference。

按照Swift标准库的定义,Void就是空元祖()

那么什么意思呢?之前提到过,如果你想表达,一个函数没有返回值的话,有三种做法。

第一种,什么也不写,这个右边

 func test() {
     
 }

第二种,右边可以写一个 -> Void

  func test() -> Void {
      
  }     

第二种,右边可以写一个 -> () 空元祖

 func test() -> () {
     
 }        

那么,为什么这么肯定呢,原因很简单。因为,如果,你去看一下Void这个定义你就会发现,在Swift标准库中有这么一句:

  public typealias Void = ()

所以,Void和()是等价的,当然你也可以自己进去看一下。


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

推荐阅读更多精彩内容