转载自泊学(boxueio.com)

在Swift 4.2中,对之前一个一直以来比容易带来困惑的类型:Implicitly Unwrapped Optional,也就是我们常说的IUO,做了一个调整(见:SE-0054)。让它从一个独立的类型,变成了Optional类型的一个修饰。简单来说,就是这样的。在之前的Swift版本里,对于下面的代码:

var a: Int? var b: Int!

其中,a的类型是Optional,而b的类型则是ImplicitlyUnwrappedOptional。而在Swift 4.2中,a和b的类型,都变成了Optional,只不过,对b来说,编译器会给它做一个标记,以便“在必要的时候”,自动unwrap它包含的值。也就是说,在4.2版本之后,无论是!还是?,代码中都只有一个optional类型,就是Optional。

对我们来说,这个改动意味着什么呢?接下来我们就总结一些和源代码兼容性相关的变化。

编译器对T!的提示

迁移到Swift 4.2之后,第一类我们最常见到的变化,就是所有编译器生成的信息中,之前包含T!的部分都会变成T?

尽管b的定义是Int!,但从编译器给出的提示中,b实际的定义则是Int?。对于这类问题,绝大多数时候,我们都可以直接把T!变成T?解决。

和 T! 相关的类型转换

接下来,由于T!已经不再是个独立的类型,因此,所有对T!的转型行为,都会被定义成过期操作:

可以看到,编译器会提示我们as T!已经是一个过期的行为,会在未来的某个Swift版本中被删除。按照SE-0045中的约束,T!变成了类型修饰之后,转型到T!应该是不被允许的,所有转型到optional的操作都应该明确使用as T?这样的用法。这个warning只是一个过渡而已。

限制了T!使用的场景

实际上,上面这个转型的限制,只是T!从类型变成类型修饰之后的某个具象的问题。在Swift 4.2里,任何一个把T!当作类型的用法,理论上都是不允许的。例如下面这两个例子:

对于数组来说,我们只能定义Array,而不能定义“包含可以自动解值的Optional的数组”。类似的,对于sum来说,我们只能定义,接受两个Optional为参数的函数,而不能定义接受两个“可以自动解值的Optional”作为参数的函数。“自动解值”,只是optional的某种特性,而不是类型的一部分。

那么,究竟可以在哪些地方使用T!呢?简单来说,就是把!当成类型修饰的地方。这听起来有点儿像废话,我们来看一些例子。

第一个,就是变量或者属性的定义中,可以使用T!:

var b: Int! = 3 class C { var attr: Int! = 0 }

无论是b还是attr,我们知道它们的类型都是Optional,只不过它们包含的值可以被编译器自动解出来而已。

第二个,是在函数的参数和返回值中,可以使用T!:

func sumFn(_ m: Int!, _ n: Int!) -> Int! { return m + n
}

这说明,sumFn接受两个Optional参数,并返回一个Optional,只不过允许编译器自动解出optional的值而已。看到这,你可能会想,为什么函数的定义中可以使用T!,但是typealias却不行呢?

很简单,对于sumFn来说,无论我们给它传递Int!还是Int?的参数,它的类型是明确的,都是(Int?, Int?) -> Int?。只不过,在sumFn的实现里,可以自动解出optional的值而已,这个性质不影响sumFn的类型。但是,对于之前的sum来说,假设它的定义是合法的,按照规则,它也会被编译器处理成:typealias sum = (Int?, Int?) -> Int?。但这样有意义么?我们的目的从字面上看本来是要定义一个支持参数和返回值都可以自动解值的函数。与其这样费力不讨好,还不如就不允许这样的行为。

返回
顶部