所以,我试图让 CGPoint
、 CGVector
和 CGSize
在使用 SpriteKit 时对我很好地工作。它们都只是具有垂直和水平分量(向量)的结构。所以我做了一个协议(protocol):VectorType
protocol VectorType {
init(x: CGFloat, y: CGFloat)
var x: CGFloat { get set }
var y: CGFloat { get set }
}
当然,我扩展了 3 个结构体以符合协议(protocol),并将
x
和 y
连接到每个结构体的水平和垂直分量,即 x
为 dx
返回 CGVector
(设置相同),x
为 width
返回 CGSize
,而对于 o 没有任何内容他们开箱即用,只是将扩展名留空。现在我重载了“主要”运算符(
CGPoint
...),所以我可以毫不费力地执行涉及不同类型结构的操作,而不必强制转换它们或创建新对象,但这里的主要事情是我也重载了这样的等价运算符://Compiler requires me to use generics for some reason
func == <T: VectorType, U: VectorType> (lhs: T, rhs: U) -> Bool {
return (lhs.x == rhs.x) && (lhs.y == rhs.y)
}
func != <T: VectorType, U: VectorType> (lhs: T, rhs: U) -> Bool {
return !(lhs == rhs)
}
现在,当我测试这段代码时,除了
+ - * /
运算符之外,一切都很好。为了测试这些运算符,我将大小与大小、大小与向量、大小与点等进行比较。当我使用 !=
时没有问题。Equal operator test
但是,当我使用
==
时出现问题。有一个像这样的 !=
:Not equal operator test
我完全明白这是从哪里来的:
Ambiguous use of operator '!='
和 ==
运算符的重载比较 !=
、 CGVector to CGVector
和 CGPoint to CGPoint
已经存在。他们是这样声明的@warn_unused_result func ==(lhs: CGSize, rhs: CGSize) -> Bool
每种类型的类(class)都有重载。所以我知道歧义的来源,它不知道在比较相同的类型时使用哪个运算符。但是我不明白为什么
CGSize to CGSize
中的==
运算符没有这种问题,如果我们基本相同的情况。对我来说这似乎是一个编译器错误,但我不确定,我尝试清理项目,重新启动 Xcode,并创建一个新项目,但仍然无法正常工作。此外,当我尝试查看导致选择
testEqual()
的歧义的其他声明时,它什么也没显示。所以,问题是:我怎样才能让它工作,或者你能提出另一种让它工作的方法(不涉及创建不同的运算符)?
更新
我发现实际上使用的
Found this candidate
和 ==
实现实际上是不同的。这是正在使用的 !=
重载的声明方式@warn_unused_result func ==(lhs: CGSize, rhs: CGSize) -> Bool
AFAIK 这也应该与我的声明相冲突,但显然没有。
这是另一个
==
重载声明。@warn_unused_result func !=<T : Equatable>(lhs: T, rhs: T) -> Bool
由于
!=
和 lhs
具有相同的类型,并且符合 VectorType 协议(protocol)的所有三种类型都符合 rhs
,因此该重载是该操作的候选者。我猜
Equatable
被使用是因为它明确要求 ==
、 CGVector
或 CGPoint
,也许这优先于泛型。如果您知道为什么两个 CGSize
运算符不冲突,不确定让我知道。 最佳答案
如果您的类型符合 Equatable
,则需要为其定义相等运算符 ==
,但是标准库根据您的相等运算符为您提供不等运算符 !=
。
(事实上,如果你查看 Equatable
protocol requirements 唯一需要的函数是 func ==
)
您的歧义错误是因为有两个定义:您自己的定义和编译器提供的定义。它们都具有相同的签名,因此编译器无法解析它。
只是不要自己定义 func !=
- 使用提供的。
如果您发现需要定义它,那么您可能并没有真正使用 Equatable
类型。
更新
你没有使用等价类型。询问一个点是否等于一个大小是没有意义的。你的问题源于试图强制它有意义。
您为每种类型的组合提供了一个 Equality 运算符。因此,您提供 CGPoint()==CGVector()
、 CGPoint()!=CGVector()
、 CGPoint()=CGSize()
和 CGPoint()!=CGSize()
,但您还提供 CGPoint()==CGPoint()
和 CGPoint()!=CGPoint()
,它们与 CoreGraphics 中的那些相冲突。继续阅读以了解为什么会收到错误消息,以及为什么 ==
似乎有效。
相等:
CGPoint、CGVector 和 CGSize 都符合 Equatable
,并提供了一个相等的运算符,其中双方都是相同的类型。
然后,您通过扩展提供了一个可用于这些类型的相等运算符:
func == <T: VectorType, U: VectorType> (lhs: T, rhs: U) -> Bool
这声明了一个适用于两个
VectorType
对象的相等运算符,即使它们具有不同的基础类型。编译器首先搜索直接匹配项,然后如果没有找到,它会尝试通过将类型替换为通用类型来生成匹配项。
因此,当您说
CGPoint()==CGPoint()
时,它将查找在 CoreGraphics 中找到的 func ==(lhs:CGPoint, rhs:CGPoint)->Bool
。当你说
CGPoint()==CGVector()
时,它会寻找 func ==(lhs:CGPoint, rhs:CGVector)->Bool
。这在 CoreGraphics 或其他任何地方都没有定义,因此它继续从通用定义构建一个。您已提供:
func == <T: VectorType, U: VectorType> (lhs: T, rhs: U) -> Bool
通过你的协议(protocol)和扩展,所以它需要你的定义,用
T
替换 CGPoint
,用 U
替换 CGVector
以产生:func == (lhs:CGPoint, rhs:CGPoint) -> Bool
它找到了一个(并且只有一个)可用的定义,所以它使用了它。
不等式:
当您说
CGPoint()!=CGPoint()
时,它将查找未定义的 func !=(lhs:CGPoint, rhs:CGPoint)->Bool
。它转向从通用定义构建一个。它发现func !=(lhs:T, rhs:T)->Bool
在标准库中,用
T
替换 CGPoint
以产生:func !=(lhs:CGPoint, rhs:CGPoint)->Bool
满足要求。
但是,由于您已经声明:
func != <T: VectorType, U: VectorType> (lhs: T, rhs: U) -> Bool
(直接或通过
Equatable
)它可以用 CGPoint 替换
T
和 U
得到:func !=(lhs:CGPoint, rhs:CGPoint)->Bool
现在它有两种方法可以满足要求。没有办法决定它应该使用哪个定义,所以它会因歧义错误而停止。
关于swift - '!=' 运算符的歧义使用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37816593/