标题就是结论,牢记!
Swift数组不具备协变特性,OC数组也不具备协变特性
《Swift进阶》一书中提到Swift的数组不具备协变特性。
译者也给出了注解,但要熟悉Java或.NET才能理解。iOSer表示概念都跟不上...
译者注:数组的协变特性指的是,包含有子类型对象的数组,可以直接赋值给包含有父类型对象的数组的变量。比如在Java和C#中string是object的子类型,而对应的数组类型string[ ]可以直接赋值给声明为object[ ]类型的变量。但是在Swift中,Array<Parent>和Array<Child>之间并没有这样的关系。
看到注解是不是很懵逼?
这里就术语结合代码谈论一下自己的理解,希望可以达到抛砖引玉的效果!
术语
__covariant(协变):子类转父类
__contravariant(逆变):父类转子类
协变和逆变都是术语,前者指能够使用比原始指定的派生类型的派生程度更大(更具体的)的类型,后者指能够使用比原始指定的派生类型的派生程度更小(不太具体的)的类型。泛型类型参数支持协变和逆变,可在分配和使用泛型类型方面提供更大的灵活性。
参考:泛型中的协变和逆变
理解:协变就是用一个子类对象去替换相应的一个父类对象,这是完全符合里氏替换原则的。(里氏替换原则:任何基类可以出现的地方,子类一定可以出现。)
逆变就是反过来用一个父类对象去替换相应的一个子类对象。
理解了概念我们再从代码的角度来看一下!
代码
//Swift
class Animal {
}
class Dog: Animal {
}
class Cat: Animal {
}
var arr: [Animal] = [Cat]()
//Swift不认为[Cat]是[Animal]的子类型,但在其中添加了一个隐式转换,现在arr就是[Animal]类型
arr.append(Animal())
//arr的元素是Animal类型的,Animal就是它的类型
arr.append(Dog())
//arr的元素是Animal类型的,Dog是它的子类型
arr.append(Cat())
//arr的元素是Animal类型的,Cat是它的子类型
print(arr)
//[SwiftCovariant.Animal, SwiftCovariant.Dog, SwiftCovariant.Cat]
上述Swift代码能正确执行,所以是隐式转换而不具有协变特性
//Java
Animal[] arr = new Cat[2]; //Java认为Cat[]是Animal[]的子类型
arr[0] = new Cat(); //arr的元素是Cat类型的,存储成功
arr[1] = new Dog(); //arr是Cat类型的,不能接受Dog类型的元素
Java代码运行报错了,因为数组类型Cat[ ]可以直接赋值给声明为Animal[ ]类型的变量,数组的协变性导致了上述错误。
回顾
了解了概念,结合着代码再回顾术语,再看书中的内容,是不是恍然大悟了😏