2016-06-14 113 views
3

所以,我试图在使用SpriteKit时使用gd CGPointCGVectorCGSize对我很好。所有这些只是具有垂直和水平分量(向量)的结构。所以,我提出的协议:VectorType对'!='运算符的模糊使用

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

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

当然,我延长了3层结构,以符合协议并连接xy到的每个结构体即水平和垂直分量x返回dxCGVector(同样为设置),x返回widthCGSize,并且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

但后来,当我使用!=有问题。有一个Ambiguous use of operator '!='这样的:

Not equal operator test

我完全得到这哪里是来自:重载的==!=运营商比较CGVector to CGVectorCGPoint to CGPointCGSize to CGSize已经存在。他们被宣布是这样的

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

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

这似乎是一个编译器bug,但我不确定,我试图清理项目,重新启动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

如果你不重写'!='定义会发生什么?它的默认实现基于'not ==' – Alexander

+0

顺便说一句,不要为自己的类型使用'CG'前缀。它通常保留CoreGraphics – Alexander

+0

嗯,我想我可以做到这一点,但它不觉得正确,我将需要手动比较这是我想要避免,但如果找不到另一个解决方案是我会走的路。是的,我正在考虑CG的事情,我会改变它,这只是我命名时首先想到的。 – lsauceda

回答

2

如果您的类型符合Equatable,您需要为它定义相等运算符==,但随后标准库会根据您的相等运算符为您提供不等式运算符!=

(事实上,如果你看一下Equatableprotocol 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 
通过您的协议和扩展

,所以需要你的定义,替代TCGPointUCGVector产生:

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

发现它的一个(和只有一个)可用的定义,所以它使用它。

不平等:

当你说CGPoint()!=CGPoint()它会寻找未被定义func !=(lhs:CGPoint, rhs:CGPoint)->Bool。它转向从通用定义中构建一个。它发现

func !=(lhs:T, rhs:T)->Bool 
标准库

,替代TCGPoint产生: FUNC =(LHS:CGPoint,RHS:CGPoint) - >布尔

满足要求。

不过,既然你已经声明:

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

(直接或通过Equatable

完全可以代替两个TU与CGPoint获得:

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

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

+1

是的,我不知道!=运算符不是必需的。无论如何,我试图不定义它,仍然没有工作,显然它是含糊不清的,因为重载(核心图形中的一个和它从equatable得到的)都可以使用,编译器会感到困惑,而不是= =运算符由于某种原因,反正请阅读更新,看看你是否知道这是为什么。尽管我解决了它,将它们全部转换为vector_float2并使用该类型的运算符 – lsauceda