https://www.raywenderlich.com/148448/introducing-protocol-oriented-programming
protocol Bird {
var name: String { get }
var canFly: Bool { get }
func doSomething()
}
protocol Flyable {
var airspeedVelocity: Double { get }
}
extension Bird {
// Flyable birds can fly!
var canFly: Bool { return self is Flyable }
func doSomething() {
print("default Bird: \(name)")
}
}
class FlappyBird: Bird, Flyable {
let name: String
let canFly = true
var airspeedVelocity: Double = 5.0
init(name: String) {
self.name = name
}
}
class Penguin: Bird {
let name: String
let canFly = false
init(name: String) {
self.name = name
}
}
class Owl<T> : Bird {
let name: String
let power: T
init(name: String, power: T) {
self.name = name
self.power = power
}
}
extension Bird where Self: FlappyBird {
func doSomething() {
print("FlappyBird: \(name)")
}
}
extension Bird where Self: Owl<String> {
func doSomething() {
print("Owl<String>: \(name)")
}
}
let fb = FlappyBird(name:"PAK")
let penguin = Penguin(name:"Mr. Pickle")
let nightOwl = Owl<String>(name:"Night Owl", power:"Who")
let dayOwl = Owl<Int>(name:"Day Owl", power: 50)
let birds: [Bird] = [fb, penguin, nightOwl, dayOwl]
birdloop: for bird in birds {
bird.doSomething()
}
我得到的输出是:
FlappyBird: PAK
default Bird: Mr. Pickle
default Bird: Night Owl
default Bird: Day Owl
第一个结果按预期工作
extension Bird where Self: FlappyBird {
func doSomething() {
print("FlappyBird: \(name)")
}
}
第二个结果按预期工作,因为它调用默认协议扩展名:
extension Bird {
// Flyable birds can fly!
var canFly: Bool { return self is Flyable }
func doSomething() {
print("default Bird: \(name)")
}
}
我希望打印的第三个结果
Owl<String>: Night Owl
因为nightOwl
属于Owl<String>
类型。但它会调用默认的协议扩展名:
default Bird: Night Owl
有什么理由
extension Bird where Self: FlappyBird {
func doSomething() {
print("default Bird: \(name)")
}
}
为FlappyBird
类型调用但
extension Bird where Self: Owl<String> {
func doSomething() {
print("Owl<String>: \(name)")
}
}
不为Owl<String>
类型调用
答案 0 :(得分:1)
对于泛型类型Owl<T>
,您可以使用约束where Self: Owl<String>
,但它只能在具体类型信息可用的上下文中使用。
要清楚说明发生了什么,请考虑以下事项:
let nightOwl = Owl<String>(name: "Night Owl", power: "Who")
nightOwl.doSomething() // prints "Owl<String>: Night Owl"
与此相反:
let nightOwl: Bird = Owl<String>(name: "Night Owl", power: "Who")
nightOwl.doSomething() // prints "default Bird: Night Owl"
当Swift为类型Owl<T>
和FlappyBird
创建协议见证表时,它必须对每个类型采取不同的行为,因为Owl
是通用的。如果它没有具体类型信息,即呼叫站点的Owl<String>
,则必须使用Owl<T>
的默认实现。这&#34;损失&#34;当您将猫头鹰插入类型为[Bird]
的数组中时,会发生类型信息。
在FlappyBird
的情况下,由于只有一种可能的实现(因为它不是通用的),编译器会生成一个带有&#34;期望&#34;的见证表。方法引用,即print("FlappyBird: \(name)")
。由于FlappyBird
不是通用的,因此其见证表不需要对doSomething()
的无约束默认实现的任何引用,因此即使缺少具体类型信息,也可以正确调用约束实现。
要明确编译器&#34;需要&#34;要获得泛型类型的回退行为,您可以从Bird
中删除Owl<T>
一致性,并尝试仅依赖于受约束的默认实现。这将导致编译错误,错误与Swift一样,具有高度误导性。
类型的价值&#39;猫头鹰&#39;没有会员&#39; doSomething&#39;
基本上,似乎无法构建见证表,因为它需要存在适用于T
上所有类型Owl
的实现。
参考
答案 1 :(得分:1)
@AllenHumphreys answer here对于部分原因是一个不错的解释。
对于修复部分,请将通用doSomething()
的{{1}}实现为:
Owl
现在您不再需要class Owl<T> : Bird {
//...
func doSomething() {
print("Owl<\(type(of: power))>: \(name)")
}
}
doSomething()
了