我正在尝试将约束协议扩展应用于结构(Swift 2.0)并接收以下编译器错误:
键入'Self'约束为非协议类型'Foo'
struct Foo: MyProtocol {
let myVar: String
init(myVar: String) {
self.myVar = myVar
}
}
protocol MyProtocol {
func bar()
}
extension MyProtocol where Self: Foo {
func bar() {
print(myVar)
}
}
let foo = Foo(myVar: "Hello, Protocol")
foo.bar()
我可以通过将struct Foo
更改为class Foo
来解决此错误,但我不明白为什么会这样做。为什么我不能将where Self:
约束协议作为结构?
答案 0 :(得分:19)
这是一种预期的行为,考虑到struct
并不意味着继承:
表示法。
实现你所描述的东西的正确方法就像是等号:
extension MyProtocol where Self == Foo {
func bar() {
print(myVar)
}
}
但是这并没有因为某些愚蠢的原因而编译:
相同类型的要求使通用参数
Self
非通用
对于它的价值,您可以通过以下方式获得相同的结果:
protocol FooProtocol {
var myVar: String { get }
}
struct Foo: FooProtocol, MyProtocol {
let myVar: String
}
protocol MyProtocol {}
extension MyProtocol where Self: FooProtocol {
func bar() {
print(myVar)
}
}
其中FooProtocol
是假的protocol
,只有Foo
应该延长。
许多尝试使用extend
标准库struct
类型的第三方库(例如,可选)都会使用与上述类似的解决方法。
答案 1 :(得分:3)
我也遇到了这个问题。虽然我也想更好地理解为什么会这样,但是Swift语言参考(指南对此没有任何说明)从通用参数部分得到以下内容:
Where子句
您可以指定类型参数及其类型的其他要求 通过在泛型之后包含where子句来关联类型 参数列表。 where子句由where关键字组成,后面跟着 以逗号分隔的一个或多个要求列表。
where子句中的要求指定了一个类型参数 从类继承或符合协议或协议 组成。虽然where子句提供了语法糖 表达对类型参数的简单约束(例如,T: 可比较等于T,其中T:Comparable等等,你可以 用它来提供更复杂的类型参数约束 他们的相关类型。例如,您可以表达约束 泛型类型T继承自类C并符合a 方案P为< T,其中T:C,T:P>。
所以'自我'看起来不可能是一个结构或者是一个假人,这是一种耻辱。据推测,有一个语言设计原因。编译器错误消息当然可以更清楚。
答案 2 :(得分:0)
由于Foo
是现有类型,您可以通过以下方式扩展:
struct Foo { // <== remove MyProtocol
let myVar: String
init(myVar: String) {
self.myVar = myVar
}
}
// extending the type
extension Foo: MyProtocol {
func bar() {
print(myVar)
}
}
来自The Swift Programming Language (Swift 2.2):
如果定义扩展以向现有类型添加新功能,则新功能将在该类型的所有现有实例上可用,即使它们是在定义扩展之前创建的。