2016-06-14 114 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