我有符合协议的结构,但是使用派生协议,而不是直接使用其父协议:
protocol A { }
protocol B: A { }
protocol C {
var property: A { get }
}
struct Foo: C {
let property: A
}
struct Bar: C {
let property: B
}
// Error: Type 'Bar' does not conform to protocol 'C'
为什么Bar
不符合要求,因为property
是A
的子协议。
答案 0 :(得分:2)
B
描述了符合某些规则集的类型。它不是本身符合这些规则的类型。 B
不符合B
,更不用说需要进一步遵守的任何内容了。 protocol B:A
说:“符合B
的任何内容也必须符合A
。”但是,B
不符合B
,因此也不符合A
。
关于SO的答案已经很多次了,但是要重复“为什么”,最简单地归结为以下示例:
protocol A {
init()
}
func f(type: A.Type) {
let a = type.init()
}
f(type: A.self)
如果A
本身符合A
,那么这应该合法。但是,init
应该调用什么f
?在存在init
和static
要求的情况下,协议不可能符合自己。
虽然原则上可以在这种情况下实现所需的特定协方差,但是Swift不能区分合法和非法协方差,因此无法全部使用。例如,考虑从不变到可变的微小变化:
protocol C {
var property: A { get set }
}
在这种情况下,Bar
绝对不可能遵循(它必须为接受{em> any property
的{{1}}提供一个设置器。尽管getter会返回A
的子类型)。 Swift无法区分所有可能的情况(通常是所有事物都是不可变的,并且没有A
或init
要求)和不可能的情况。在技术上可行的情况下,已经进行了一些讨论,但令人担忧的是,对协议进行很小的更改可能会破坏您的整个类型结构,有时是出于非显而易见的原因。相反,至少到目前为止,类型要求通常是不变的。
解决此整体问题的一种典型方法是仅提供所需类型的访问器。例如:
static
这提供了更大的灵活性(您可以根据需要将protocol A { }
protocol B: A { }
protocol C {
var aProperty: A { get }
}
struct Foo: C {
let aProperty: A
}
struct Bar: C {
var aProperty: A { return bProperty }
let bProperty: B
}
设为bProperty
),并使代码更明确。