protocol Animal {
func makeNoise()
static var species: String { get }
}
struct Dog: Animal {
func makeNoise() { print("Woof") }
static var species: String = "Canus familiaris"
}
struct Cat: Animal {
func makeNoise() { print("Meow") }
static var species: String = "Felis catus"
}
var animal: Animal // `Animal` is used here as a type.
animal = Dog()
animal.makeNoise() // Prints "Woof".
animal = Cat()
animal.makeNoise() // Prints "Meow".
func declareAnimalSpecies<T: Animal>(_ animal: T) {
animal.makeNoise()
print("My species is known as (T.species)")
}
let dog = Dog()
declareAnimalSpecies(dog)
// Prints:
// "Woof"
// "My species is known as Canus familiaris"
declareAnimalSpecies(animal) // <- not show error here
// error: protocol type 'Animal' cannot conform to 'Animal'...`
我从 swift git 获取示例代码。据我了解
animal
的类型是 any Animal
所以当它传递给函数 declareAnimalSpecies
时,编译器会推断 T 是 any Animal
并且因为 any Animal cannot conform to Animal
所以我希望它会显示错误。
自实施SE-0352以来这是允许的。这允许我们在调用泛型方法时“打开存在框”。
animal
是一个存在的“盒子”,在运行时,它保存一个符合 Animal
内部的实际具体类型。现在,编译器不再仅仅查看类型约束并说“any Animal
不符合Animal
”,而是可以看到这是一个盒子,并且其中必须有“某种具体类型”。在运行时,保证有一个T
符合其类型约束。作为反例,请考虑
func foo<T: Animal>(_ a: T, _ b: T) {}
func bar(_ a: any Animal, _ b: any Animal) {
foo(a, b) // error
}
这是不允许的,因为存在框
a
和
b
在运行时可能包含不同的具体类型,因此不一定有单个 T
类型可以传递给 foo
。
需要注意的是,从类型系统的 POV 来看,any Animal
still不符合
Animal
。如果你有struct Foo<T: Animal> {}
你还是做不到
Foo<any Animal>
。