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实施以来允许的。这允许我们在调用泛型方法时“打开存在性框”。SE -0375进一步允许我们对可选参数执行相同操作。
animal
是一个存在性“盒子”,在运行时,它包含一个符合其类型约束的实际具体类型。编译器现在能够看到这是一个盒子,并且其中必须有某种具体类型Animal
,而不是仅仅查看类型约束并说“any Animal
不符合”。在运行时,可以保证存在符合其类型约束的。Animal
T
作为反例,考虑
这是不允许的,因为存在框
a
和b
在运行时可能包含不同的具体类型,所以不一定存在T
可以传递给的单一类型foo
。值得注意的是,从类型系统的角度来看,
any Animal
仍然不符合Animal
。如果你有你仍然无法写
Foo<any Animal>
。在这种情况下,没有存在性的框可以打开。