为什么我会收到错误消息“Protocol … can only be used as a generic constraint because it has Self or associated type requirements”?

Why do I get the error “Protocol … can only be used as a generic constraint because it has Self or associated type requirements”?

我在 Int 上写了一个扩展,如下所示。

extension Int {
    func squared () -> Int {
        return self * self
    }
}

print(10.squared()) // works

以上代码有效。现在我想扩展 IntegerType 协议,使 Int、UInt、Int64 等都符合要求。我的代码如下。

extension IntegerType {

    func squared () -> IntegerType { // this line creates error

        return self * self

    }
}

我收到错误:

Protocol 'IntegerType' can only be used as a generic constraint because it has Self or associated type requirements

我已经看到了this question and its video & this题,还是没看懂。我只知道有一些 associatedType 在这种情况下是 Self 但无法连接点。我觉得我对 Generics 主题缺乏了解也是一个原因...

有人可以详细说明一下这个主题吗?为什么扩展会产生错误?

你只需要 return Self

edit/update:

注意:您可以在 Swift 中扩展所有数字类型(整数和浮点数) 4 扩展数字协议

Swift 4

extension Numeric {
    func squared() -> Self {
        return self * self
    }
}

Swift 3

extension Integer {
    func squared() -> Self { 
        return self * self
    }
}

函数return类型只能是具体的Type

重点是类型。 任何完全在自身定义的结构,class 或协议都是纯类型。 但是当协议或结构依赖于另一个通用类型占位符时,例如 T , 那么这是一个部分类型。

类型是编译器必须分配一定内存的数据结构。

所以像这样:

let a = Array<T>()let b = T 的信息不足以让编译器在编译时进行推断。

因此,这行不通。

  extension IntegerType {

    func squared () -> IntegerType { // this line creates error

        return self * self

    }
}

这里,IntegerType 是分部类型。它是一个通用协议,只有在符合时我们才能知道确切的类型。类似于数组。数组本身不是一种类型。它是一个通用容器。只有当有人使用 Array() 或 Array()... 创建它时,它才有类型。

同样的事情也发生在你身上。

public protocol IntegerType : _IntegerType, RandomAccessIndexType {

然后,

public protocol RandomAccessIndexType : BidirectionalIndexType, Strideable, _RandomAccessAmbiguity {
@warn_unused_result
    public func advancedBy(n: Self.Distance) -> Self

然后,

   public protocol _RandomAccessAmbiguity {
    associatedtype Distance : _SignedIntegerType = Int
   }

因此,由于 RandomAccessIndexType 具有自我要求的含义,直到并且除非有人符合它,否则自我是未知的占位符。它是部分类型。

因为 IntegerType 符合 RandomAccessIndexType 和 _RandomAccessAmbuiguity,这也需要 Distance 关联类型。

所以你也不能这样做

let a: IntegerType = 12

同样 IntegerType 需要知道 Self 和 Distance (associatedType)。

Int 然而提供了这样的细节

public struct Int : SignedIntegerType, Comparable, Equatable {
    /// A type that can represent the number of steps between pairs of
    /// values.
    public typealias Distance = Int

因此你可以这样做

let a:Int = 10

因为它为 SignedIntegerType 提供了 Self,为它的另一个对应物提供了 Distance。

简单地说:

可以使用具体类型的地方不能使用分部类型。部分类型适用于其他泛型并对其进行约束。