想起自己学习Swift也有一段时间了,想先从Swift中的标准库中的函数看起,理解苹果工程师是如何从命名、参数、返回值来最终构建一个标准函数的,相信这对我日后的学习使用都会有很大的帮助。
Array中的map函数:
为数组中的每一个元素(Element,这个也是个范型哦,可以是任意类型)做一次操作后返回一个数组。
public func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]
**函数构成**:
* public:访问修饰符,表示这个方法在本模块之外是不能被继承的,而这个模块的区分是按framework为单位
* func:构建方法关键字
* map:函数名称
* <T>:这是Swift范型的一种用法,**其中T表示一种任意类型,这个T我们也可以换成其他的字母,并不影响结果**
* (_ transform: (Element) throws -> T):函数名后面的括号表示参数,**其中transform表示参数名字,而transform前面的 ‘_’ 则是省略外部参数的意思。注意到后面一部分(Element) throws -> T ,这是个函数,表示传递一个函数类型的参数进去**
> `(Element) throws -> T` ,这一部分我单独提出来,因为这里涉及到好几个知识点。
这是函数当作参数的一种用法,它表示把数组中的每一个元素Element当作这个函数的参数,进行一次操作后,返回T类型,throws表示当出现问题时会抛出异常。
**当函数作为一个参数时,就是在作为一个闭包(closure)在使用**。
下面我列举一个OC中的闭包用法:
```Objective-C
- (void)doSomethingWithComplication:(void(^)(BOOL finished))complication;
// 调用上面的方法
[self doSomethingsWithComplication:^(BOOL finished){
// 你的逻辑
}]
可以看出来,OC中的闭包也是给方法传递了一个‘函数’参数,所以两者在调用上都是相同的。
在Swift3.0中,有个官方的关于map的例子:
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]
// 将numbers的数字转换成英文字符串数组
let strings = numbers.map {
number -> String in
var number = number//将常量转成变量,因为我们要在下面做循环递除。这两个number是不同的,按Option左键点击可看到,它们一个是var,一个let的,编译器会作区分
var output = ""
repeat {
output = digitNames[number % 10]! + output
number /= 10
} while number > 0
return output
}
// strings 常量被推断为字符串类型数组,即 [String]
// 其值为 ["OneSix", "FiveEight", "FiveOneZero"]
我一开始天真的以为可以做下面的简化:
let strings2 = numbers.map {
var n = $0
var output = ""
repeat {
output = digitNames[n % 10]! + output
n /= 10
} while n > 0
return output
}
然而这样做并不行,编译器提示说不能推断出closure的返回类型。这时,我们注意到这个闭包的返回类型是个T,也就是个范型。在这里,我不明白为什么编译器不能从返回值中推断出这个closure返回的是个String类型呢?没办法,必须显示指出返回值是个String。
但是下面的却是可以的:为数组numbers的每个元素➕10
numbers.map({
$0 + 10
})
由此,我推断编译器的类型推断应该只是从数组numbers中的类型里面推断出来的,如果closure中的返回值改变,必须显示指出。