我正在尝试像这样实现一个基本的协议(protocol)扩展:
protocol Value {
func get() -> Float
mutating func set(to:Float)
}
extension Value {
static func min(of a:Value, and b:Value) -> Float {
if a < b { //Expression type 'Bool' is ambiguous without more context
return a.get()
}else{
return b.get()
}
}
static func < (a:Value, b:Value) -> Bool {
return a.get() < b.get()
}
}
在 if
子句中,编译器说:Expression type 'Bool' is ambiguous without more context
。为什么这行不通?
最佳答案
如前所述in this Q&A ,实现为 static
的运算符重载之间存在差异成员和运算符重载实现为顶级函数。 static
成员额外(隐式)self
编译器需要能够推断出的参数。
那么self
的值是多少呢?推断?好吧,它必须从重载的操作数或返回类型来完成。对于协议(protocol)扩展,这意味着其中一种类型需要是 Self
.请记住,您不能直接调用类型上的运算符(即您不能说 (Self.<)(a, b)
)。
考虑以下示例:
protocol Value {
func get() -> Float
}
extension Value {
static func < (a: Value, b: Value) -> Bool {
print("Being called on conforming type: \(self)")
return a.get() < b.get()
}
}
struct S : Value {
func get() -> Float { return 0 }
}
let value: Value = S()
print(value < value) // Ambiguous reference to member '<'
self
的值是多少?在调用 <
?编译器无法推断它(我真的认为它应该直接在重载上出错,因为它是不可调用的)。请记住 self
在协议(protocol)扩展中的静态范围内必须是具体符合类型;它不能只是Value.self
(因为协议(protocol)扩展中的静态方法仅可用于调用具体的符合类型,而不是协议(protocol)类型本身)。
我们可以通过将重载定义为顶级函数来修复上面的示例和您的示例:
protocol Value {
func get() -> Float
}
func < (a: Value, b: Value) -> Bool {
return a.get() < b.get()
}
struct S : Value {
func get() -> Float { return 0 }
}
let value: Value = S()
print(value < value) // false
这是可行的,因为现在我们不需要推断 self
的值.
我们还可以为编译器提供一种方法来推断 self
的值,通过使一个或两个参数取 Self
:
protocol Value {
func get() -> Float
}
extension Value {
static func < (a: Self, b: Self) -> Bool {
print("Being called on conforming type: \(self)")
return a.get() < b.get()
}
}
struct S : Value {
func get() -> Float { return 0 }
}
let s = S()
print(s < s)
// Being called on conforming type: S
// false
编译器现在可以推断出 self
来自静态类型的操作数。但是,如上所述,这需要是具体类型,因此您不能处理异构 Value
操作数(您可以使用一个操作数采用 Value
;但不能同时使用两个,因为那样就无法推断出 self
)。
但请注意,如果您提供 <
的默认实现,您可能还应该提供 ==
的默认实现.除非你有充分的理由不这样做,否则我还建议你让这些重载采用同质的具体操作数(即 Self
类型的参数),这样它们就可以为 Comparable
提供默认实现。 .
也不是 get()
和 set(to:)
要求,我建议改用可设置的属性要求:
// Not deriving from Comparable could be useful if you need to use the protocol as
// an actual type; however note that you won't be able to access Comparable stuff,
// such as the auto >, <=, >= overloads from a protocol extension.
protocol Value {
var floatValue: Double { get set }
}
extension Value {
static func == (lhs: Self, rhs: Self) -> Bool {
return lhs.floatValue == rhs.floatValue
}
static func < (lhs: Self, rhs: Self) -> Bool {
return lhs.floatValue < rhs.floatValue
}
}
最后,如果Comparable
一致性对于符合 Value
至关重要, 你应该让它派生自 Comparable
:
protocol Value : Comparable {
var floatValue: Double { get set }
}
你不应该需要 min(of:and:)
在任何一种情况下都起作用,因为当符合类型符合 Comparable
时, 它可以使用顶级 min(_:_:)
功能。
关于swift - 快速理解协议(protocol)扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47931606/