作为一名程序员,我们是不会甘心止步于语法的“甜”,我们有永恒的动力去揭开这层语法的外衣一看究竟:)。我们在《Optional chaining的秘密(一)》中指出了,在类型的后面使用?
表示Optional类型,而?.
则是map
方法的语法糖。
我们今天要研究的是在类型的后面使用!
意味着什么?
ImplicitlyUnwrappedOptional
只要我们随便翻翻官方文档,我们就能知道,下面这段代码是编译不过的
let x: String? = "Hello,world"
func printString(str: String) {
print(str)
}
printString(x) // error!!!!!!
原因就在于 x
被 String?
声明为一个Optional<String>类型了,而方法printString()要求的参数是 String
类型,所以如果直接传递 x
会导致调用失败,如果我们希望方法调用成功,那么我们需要这样处理。
printString(x!)
我们需要使用 !
强制对 x
进行拆封,使其还原为 String
类型。那么如果 !
放在类型的后面意味着什么呢?
let x: String! = "Hello,world"
func printString(str: String) {
print(str)
}
printString(x) // ok!!!!!!
文档把这种 let x: String!
称为隐式拆封(implicitly unwrapped),在 implicitly unwrapped
的帮助下,我们可以看到printString(x)
中的参数x
不需要强制拆封了。难道let x: String!
为我们定义了一个String
类型?no,no,no,no
我们在看一个长一点的例子。
public class Demo {
public var subDemo: SubDemo! = nil
}
public class SubDemo {
public let count: Int = 1
}
let demo: Demo! = Demo()
demo.subDemo = SubDemo()
let count = demo.subDemo.count
在这个代码片段中,我们有两处值得注意:
-
public var subDemo: SubDemo! = nil
可以被声明为nil -
let count = demo.subDemo.count
可以chaining式调用
第一点是比较容易解释的,subDemo
之所以可以被声明为nil是因为,SubDemo!
声明了一个ImplicitlyUnwrappedOptional
类型,也就是说它不是一个普通的类型,如果它是一个普通的SubDemo
类型,那么它一定不允许为nil.
如何完成链式的调用
那怎么解释第二点,链式调用呢?让我们循序渐进,我们现在有这样个方法,可以给一个string做扩展
extension String {
static func appendingString(str: String) -> (String) -> String {
return { str + $0 }
}
}
var aStr = "Hello"
var bString = String.appendingString(aStr)("!")
var method = String.appendingString(aStr)
var cStr = method("!")
现在我们定义个操作符方法:+-
它可以帮助我们实现上面同样的功能
infix operator +- { associativity left }
func +-<T,Z>(obj:T, f:T->Z) -> Z {
return f(obj)
}
通过这个中缀操作符的定义,我们可以这样实现给一个字符做扩展的功能。
let helloString = "hello" +- {
String.appendingString($0)("!")
}
操作符 +-
接收两个参数,一个是字符串"hello"
,另外一个是闭包。而且通过associativity
的声明,这种操作可以还可以产生一个连缀式调用。
let helloString = "hello" +- {
String.appendingString($0)("!")
} +- { String.appendingString($0)("!") }
说了这么多,不知道我们又没有注意,我们现在已经可以对 String 类型做类似 ?.
操作了,只是当前类型是String
,我们现在要将其适用于ImplicitlyUnwrappedOptional
类型。
infix operator +- { associativity left }
func +-<T,Z>(obj:ImplicitlyUnwrappedOptional<T>, f:T->Z) -> ImplicitlyUnwrappedOptional<Z> {
switch obj {
case .Some(let x):
return f(x)
case .None:
fatalError()
}
}
我们重新实现操作符 +-
的定义,使其接收一个ImplicitlyUnwrappedOptional
类型的参数并返回一个ImplicitlyUnwrappedOptional
类型的值。方法体内容会对参数obj
进行拆包,如果为nil
则会报错,否则经过转换后返回ImplicitlyUnwrappedOptional
,这不就是完整的implicitly unwrapped
的工作过程吗?好,现在我们把String声明为implicitly unwrapped
var oldString: String! = "hello" // String!
let helloString = oldString +- {
String.appendingString($0)("!")
} +- { String.appendingString($0)("!") }
这就是Optinal chaining
在 implicitly unwrapped
是的工作过程。
总结
以上代码在xcode 7.3上都测试通过。虽然代码没有swift的链式操作符代码那样漂亮,但这些功能确实可以通过纯swift代码来实现。希望这些内容有助于大家对optional
更深入的理解。