Structs上的协议扩展导致编译错误“Self”约束为非协议类型

时间:2015-09-30 10:16:41

标签: swift

我正在尝试将约束协议扩展应用于结构(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:约束协议作为结构?

3 个答案:

答案 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)

  

如果定义扩展以向现有类型添加新功能,则新功能将在该类型的所有现有实例上可用,即使它们是在定义扩展之前创建的。