编译器不显示错误“协议类型'P'不能符合'P'”

问题描述 投票:0回答:1
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
所以我希望它会显示错误。

swift
1个回答
0
投票

自实施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>

    

© www.soinside.com 2019 - 2024. All rights reserved.