swift – 使用关联类型和泛型错误

前端之家收集整理的这篇文章主要介绍了swift – 使用关联类型和泛型错误前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
以下代码给我一个在线返回p.foo(self)的错误.错误说:’P’没有名为’foo’的成员.
protocol P {
  typealias T
  func foo(c: C<T>) -> T
  func foo2() -> T
}

class C<T> {
  var p: P
  init (p: P) {
    self.p = p
  }
  func bar() -> T {
    return p.foo(self);
  }
}

协议P定义了与任何专门的C类型正确匹配的关联类型.我错过了什么吗?或不?

在回答问题之前,我会重新命名这些类型,以使问题更清晰一些:
protocol P {
  typealias ElementType
  func foo(c: C<ElementType>) -> ElementType
  func foo2() -> ElementType
}

class C<T> {
  var p: P
  init (p: P) {
    self.p = p
  }
  func bar() -> T {
    return p.foo(self)
  }
}

在这种情况下,您会收到三个编译错误

error: <EXPR>:8:12: error: protocol 'P' can only be used as a generic constraint because it has Self or associated type requirements
    var p: P
           ^
<EXPR>:9:14: error: protocol 'P' can only be used as a generic constraint because it has Self or associated type requirements
    init (p: P) {
             ^
<EXPR>:13:16: error: 'P' does not have a member named 'foo'
        return p.foo(self)
               ^ ~~~

有趣的是第一个/第二个(他们指出相同的问题):“协议’P’只能用作通用约束,因为它具有自我或相关类型要求”.
所以问题是相关联的类型.在当前配置中,您指定了初始化程序和变量的参数类型为P.但是,由于您为P指定了一个关联类型,所以该类型不足以作为正确类型使用.只有实际指定可以使用ElementType的子类型.但是,您可以指定必须是P的子类型的通用参数.在初始化程序的情况下,您可以编写

init <S:P>(p: S) {
    self.p = p
}

这将消除初始化程序的编译器错误.现在编译器知道参数必须是P的子类型,有效的子类型总是指定ElementType是什么,所以它是快乐的.

但这并不能帮助你:

var p: P

您仍然不能在这里使用不完整的类型P.你可能想要使用S,但是在这个时候,初始化器中的S和S之间没有连接,你将使用它作为变量的类型,但是它们显然需要相同.
时间为您的课程介绍第二个通用参数:

class C<T,S:P> {
    var p: S
    init (p: S) {
        self.p = p
    }
    func bar() -> T {
        return p.foo(self)
    }
}

几乎完成了,现在你有一个正确指定的类型用于你的变量.但是没有你的协议规范是不正确的:

func foo(c: C<ElementType>) -> ElementType

C现在需要两个参数,您需要在这里指定.我们想在这里使用`C,但是我们不能:

错误::3:17:错误

: type 'P' does not conform to protocol 'P'
    func foo(c: C<ElementType,P>) -> ElementType
                ^
<EXPR>:2:15: note: associated type 'ElementType' prevents protocol from conforming to itself
    typealias ElementType

由于P未指定相关类型的ElementType,它不正确符合P,并且不能在符合P类型的地方使用.但有一个很好的特殊类型:自我.这引用了实现协议的实际类型,所以我们可以写下列内容

protocol P {
    typealias ElementType
    func foo(c: C<ElementType,Self>) -> ElementType
    func foo2() -> ElementType
}

现在我们指定由任何确认类型实现的foo函数实际上使用指定的ElementType和实现类型本身的C.花哨,不是吗?

但是我们尚未完成,最后一个错误仍然存​​在:

error: <EXPR>:13:18: error: cannot convert the expression's type 'T' to type 'S.ElementType'
        return p.foo(self)

此时编译器知道如下:

> p.foo(self)返回S的ElementType
>函数bar()应返回T类型

但是没有什么可以告诉的,ElementType和T实际上是一样的,所以它不能确定这是否有效和抱怨.所以我们实际想要的是,S的ElementType总是和T一样,我们可以指定:

class C<T,S:P where S.ElementType == T> {

完整代码

protocol P {
    typealias ElementType
    func foo(c: C<ElementType,Self>) -> ElementType
    func foo2() -> ElementType
}

class C<T,S:P where S.ElementType == T> {
    var p: S
    init (p: S) {
        self.p = p
    }
    func bar() -> T {
        return p.foo(self);
    }
}

猜你在找的Swift相关文章