模糊地使用'!='运算符

时间:2016-06-14 15:44:10

标签: swift operator-overloading core-graphics ambiguous

所以,在尝试使用SpriteKit时,我正试图让CGPointCGVectorCGSize很好地为我工作。所有这些都只是具有垂直和水平分量(向量)的结构。所以我制定了一个协议:VectorType

protocol VectorType {
    init(x: CGFloat, y: CGFloat)

    var x: CGFloat { get set }
    var y: CGFloat { get set }
}

当然,我扩展了3个结构以符合协议,并将xy连接到每个结构的水平和垂直分量,即x返回dx对于CGVector(设置相同),x会为width返回CGSize,而CGPoint则不会为+ - * /提供任何内容,因为它们开箱即用扩展名为空。

现在我重载了“main”运算符(//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

然后,当我使用Ambiguous use of operator '!='时出现问题。这样有一个==

Not equal operator test

我完全了解它的来源:比较!=CGVector to CGVectorCGPoint to CGPoint的{​​{1}}和CGSize to CGSize运算符的重载已经存在。它们被声明为

@warn_unused_result func ==(lhs: CGSize, rhs: CGSize) -> Bool

每种类型的课程都有过载。所以我得到了模糊性的来源,它不知道在比较相同的类型时使用哪个运算符。但是我不明白为什么==中的testEqual()运算符没有这样的问题,如果我们基本上有相同的情况。

这似乎是一个编译器错误,但我不确定,我尝试清理项目,重新启动Xcode,并创建一个新项目,但仍然无法正常工作。另外,当我试图看到引起歧义选择Found this candidate的其他声明时,它只显示任何内容。

所以,问题是:我怎样才能使它工作,或者你能建议另一种方法使它工作(不涉及创建不同的运算符)?

更新

我发现实际使用的==!=实现实际上是以不同方式声明的。这就是声明使用==重载的方式

@warn_unused_result func ==(lhs: CGSize, rhs: CGSize) -> Bool

AFAIK这也应该与我的声明相冲突,但显然没有。

这是另一个!=重载声明。

@warn_unused_result func !=<T : Equatable>(lhs: T, rhs: T) -> Bool

由于lhsrhs具有相同的类型,并且符合VectorType协议的所有三种类型都符合Equatable,因此该重载是该操作的候选者。

我想==会被使用,因为它明确要求CGVectorCGPointCGSize,并且可能优先于泛型。如果您知道为什么两个==运营商都不会发生冲突,请不要告诉我。

1 个答案:

答案 0 :(得分:2)

如果您的类型符合Equatable,则需要为其定义等于运算符==,然后标准库为您提供不等式运算符!=。运营商。

(事实上,如果您查看Equatable protocol requirements,唯一需要的功能是func ==

您的歧义错误是因为有两个定义:您自己的定义和编译器提供的定义。它们都具有相同的签名,因此编译器无法解析它。

不要自己定义func != - 使用提供的。

如果您发现需要定义它,那么您可能并不真正使用Equatable类型。

<强>更新

你没有使用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

通过您的协议和扩展程序,因此需要您的定义,将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) - &gt; Bool

满足要求。

但是,因为你已宣布:

func != <T: VectorType, U: VectorType> (lhs: T, rhs: U) -> Bool

(直接或通过Equatable

它可以用CGPoint替换TU来获取:

func !=(lhs:CGPoint, rhs:CGPoint)->Bool

现在有两种方法可以满足要求。没有办法决定它应该使用哪个定义,所以它会因模糊错误而停止。