为啥我会收到错误“协议……只能用作通用约束,因为它具有自身或关联的类型要求”?
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 内部实现协议的一部分。尽管您可以公开访问它们,但我不会这样做。 我的意思是_IntegerType
和IntegerType
有什么区别?
任何遵循 _ 的协议都表示该协议不应公开使用。这是 Swift 标准库实现的一部分。他们将一次又一次地修改这个内部协议,使其符合高级视图。如果你确实公开使用这个,尽管 Xcode 不会建议,当内部发生变化时你可能需要重做。
一年多了。而且我慢慢地开始在我的代码中使用泛型并且有了更好的理解。 2 个问题: 1. 编译器在编译时推断的信息不足。 我不明白。我的意思是泛型参数的类型在其所有功能中本质上是未知的。为什么你写的扩展不能一样。为什么这有什么不同? 2. 另外你说:函数返回类型只能是具体类型。但是很多函数返回T
。这和你刚才说的不矛盾吗?以上是关于为啥我会收到错误“协议……只能用作通用约束,因为它具有自身或关联的类型要求”?的主要内容,如果未能解决你的问题,请参考以下文章
“协议......只能用作通用约束,因为它具有 Self 或关联的类型要求”是啥意思?