Optional chaining的秘密(二)

作为一名程序员,我们是不会甘心止步于语法的“甜”,我们有永恒的动力去揭开这层语法的外衣一看究竟:)。我们在《Optional chaining的秘密(一)》中指出了,在类型的后面使用?表示Optional类型,而?.则是map 方法的语法糖。

我们今天要研究的是在类型的后面使用!意味着什么?

ImplicitlyUnwrappedOptional

只要我们随便翻翻官方文档,我们就能知道,下面这段代码是编译不过的

let x: String? = "Hello,world"
func printString(str: String) {
    print(str)
}
printString(x) // error!!!!!!

原因就在于 xString? 声明为一个Optional类型了,而方法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 +-(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 +-(obj:ImplicitlyUnwrappedOptional, f:T->Z) -> ImplicitlyUnwrappedOptional {
    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 chainingimplicitly unwrapped 是的工作过程。

总结

以上代码在xcode 7.3上都测试通过。虽然代码没有swift的链式操作符代码那样漂亮,但这些功能确实可以通过纯swift代码来实现。希望这些内容有助于大家对optional更深入的理解。

你可能感兴趣的:(Optional chaining的秘密(二))