为啥我会收到错误“协议……只能用作通用约束,因为它具有自身或关联的类型要求”?

Posted

技术标签:

【中文标题】为啥我会收到错误“协议……只能用作通用约束,因为它具有自身或关联的类型要求”?【英文标题】:Why do I get the error “Protocol … can only be used as a generic constraint because it has Self or associated type requirements”?为什么我会收到错误“协议……只能用作通用约束,因为它具有自身或关联的类型要求”? 【发布时间】:2016-09-05 23:18:21 【问题描述】:

我在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' 只能用作通用约束,因为它具有 Self 或关联的类型要求

我已经看过this问题及其视频和this问题,还是看不懂。我只知道有一些associatedType 在这种情况下是Self 但无法连接点。我觉得我对Generics 主题缺乏了解也是一个原因......

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

【问题讨论】:

另外,请务必查看this Medium post,它提供了关于该问题的出色见解。 【参考方案1】:

您只需返回Self

编辑/更新:

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

斯威夫特 4

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


斯威夫特 3

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

【讨论】:

Leo,你能看看这个comment接受的答案吗?我认为答案有些错误,而您的答案是正确的。我对吗?你能详细说明一下吗?除了新的Numeric 协议之外,Swift4 中还有什么新的东西会影响这个问题吗? @Honey 没有什么可详细说明的。接受的答案解释了您为什么会收到错误,这就是您所要求的。我刚刚为您的问题提供了解决方案。请注意,您可以决定将哪一项标记为正确。【参考方案2】:

函数返回类型只能是具体的Type

重点是类型。 任何自己完全定义的结构、类或协议都是纯类型。 但是当一个协议或结构依赖于另一个通用类型占位符(例如 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 具有 Self 要求含义,除非有人遵守它,否则 Self 是未知占位符。它是部分类型。

由于 IntegerType 符合 RandomAccessIndexType 和 _RandomAccessAmbuiguity ,这也需要与距离相关的类型。

所以你也不能这样做

let a: IntegerType = 12

IntegerType 再次需要知道 Self 和 Distance(关联类型)。

然而,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。

简单地说:

不能在具体类型可以使用的地方使用部分类型。部分类型适用于其他泛型并限制它们。

【讨论】:

下划线是什么意思? 它们是 swift 内部实现协议的一部分。尽管您可以公开访问它们,但我不会这样做。 我的意思是_IntegerTypeIntegerType有什么区别? 任何遵循 _ 的协议都表示该协议不应公开使用。这是 Swift 标准库实现的一部分。他们将一次又一次地修改这个内部协议,使其符合高级视图。如果你确实公开使用这个,尽管 Xcode 不会建议,当内部发生变化时你可能需要重做。 一年多了。而且我慢慢地开始在我的代码中使用泛型并且有了更好的理解。 2 个问题: 1. 编译器在编译时推断的信息不足。 我不明白。我的意思是泛型参数的类型在其所有功能中本质上是未知的。为什么你写的扩展不能一样。为什么这有什么不同? 2. 另外你说:函数返回类型只能是具体类型。但是很多函数返回T。这和你刚才说的不矛盾吗?

以上是关于为啥我会收到错误“协议……只能用作通用约束,因为它具有自身或关联的类型要求”?的主要内容,如果未能解决你的问题,请参考以下文章

“协议......只能用作通用约束,因为它具有 Self 或关联的类型要求”是啥意思?

“协议......只能用作通用约束,因为它具有 Self 或关联的类型要求”是啥意思?

如何在 swiftUI 中创建一个普通视图

为啥我会收到这种错误验证错误?

为啥我会收到此错误

为啥我会收到错误数量的参数错误?