Swift|Swift 3关于函数类型的一项重要提议
本系列文章为个人学习笔记:禁止转载对于一个函数来说,把它的参数和返回值放在一起,就形成了它的签名,这是用于描述函数自身属性的一种类型。
参数名称不再是函数类型的一部分 不过没关系,我们从一个简单的例子开始。对于上一节中,我们实现的
mul
:func mul(m: Int, of n: Int) -> Int {
return m * n
}
如果我们用type inference定义一个和
mul
类型相同的函数变量:let fnMul = mul
之后,我们该如何使用
fnMul
呢?在Swift 2里,是这样的:// ONLY 6 in Swift 2
// WRONG in Swift 3
fnMul(m: 2, n: 3)
而到了Swift 3里,编译器会报错。
所以我们只能这样使用
fnMul
:fnMul(2, 3) // 6
这说明什么呢?从结果上来看
m:n:
已经在不再是mul
签名的一部分了。在Swift 3里,mul
和fnMul
的类型,实际上都是:(Int, Int) -> Int
。然而,为什么要做这样的改动呢?我们继续来看一个在Swift 2中因为函数签名带来的诡异的问题。
假设,我们还有一个用于计算整数除法的函数:
func div(a: Int, b: Int) -> Int {
return a / b
}
然后,对于下面这段代码,你期望最后
fnDiv
得到什么结果呢?// !!! Swift 2 ONLY !!!
var fnDiv: (a: Int, b: Int) -> Int = div
fnDiv = mulfnDiv(a: 2, b: 3) // This will call mul(m: 2, n: 3)
// !!! Swift 2 ONLY !!!
【Swift|Swift 3关于函数类型的一项重要提议】结果会是6,
fnDiv(a: 2, b: 3)
实际上调用了mul
。造成这个结果的原因有2:- 首先,
mul
和div
都接受2个Int
作为参数,并返回一个Int
,因此,尽管它们的参数名不同,但它们的类型是兼容的,我们可以让fnDiv = mul
; - 其次,由于参数名又是函数签名的一部分,我们使用
fnDiv
的时候,必须带上a:b:
;
div
的用法,而暗地里执行了mul
的错觉。如果这段代码隐藏在你的源文件中,你能轻易发现问题的原因么?正是由于这种原因,在Swift 3里,参数名不再是函数签名的一部分了,
mul
和div
的类型都是(Int, Int) -> Int
。这样:- 之前我们定义的
fnMul
,只能用fnMul(2, 3)
这样的形式调用; - 无论
fnMul
被赋值成任何函数,调用方式都是统一的:fnMul(num1, num2)
,这样就不会有因为参数名带来的调用错觉了;
简单来说,就是函数这种类型,和Swift其它类型有着完全相同的语法功能。它们主要包括:
- 可以用来定义变量,例如我们之前定义的
fnMul
和fnDiv
,这种类型的变量同样可以当作函数来调用; - 可以当成函数参数;
- 可以被函数返回;
func calc(_ first: T,
_ second: T,
_ fn: (T, T) -> T) -> T {
return fn(first, second)
}
在这个函数的定义里,
calc
就接受一个函数类型的参数,然后,我们可以像传递数字一样,来传递函数变量:calc(2, 3, mul) // 6
calc(2, 3, div) // 0
类似的,我们也可以把函数类型当成返回值,例如下面这个有点儿特殊的
mul
方法:func mul(_ a: Int) -> (Int) -> Int {
func innerMul(_ b: Int) -> Int {
return a * b
}return innerMul
}
它只接受一个参数,并返回一个函数,在返回的函数里,接受另外一个参数,并最终完成相乘的运算。因此,我们可以用两种不同的方式来调用它:
let mul2By = mul(2)
mul2By(3) // 6mul(2)(3) // 6
第一种方式,我们先用一个变量保存
mul
返回的函数,然后通过再传递一个单参数来最终完成运算。或者,我们可以直接通过()
把两次函数调用串联起来。因此,尽管currying function在Swift 3中被废除了,但我们还是可以通过这样的方法来实现同样的效果。推荐阅读
- 关于QueryWrapper|关于QueryWrapper,实现MybatisPlus多表关联查询方式
- 四首关于旅行记忆的外文歌曲
- 醒不来的梦
- 一起来学习C语言的字符串转换函数
- C语言字符函数中的isalnum()和iscntrl()你都知道吗
- C语言浮点函数中的modf和fmod详解
- C语言中的时间函数clock()和time()你都了解吗
- 关于自我为中心的一点感想
- 「按键精灵安卓版」关于全分辨率脚本的一些理解(非游戏app)
- 概率论/统计学|随机变量 的 分布函数 与 概率密度函数 的区别