所以,我试图让 CGPointCGVectorCGSize 在使用 SpriteKit 时对我很好地工作。它们都只是具有垂直和水平分量(向量)的结构。所以我做了一个协议(protocol):VectorType

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

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

当然,我扩展了 3 个结构体以符合协议(protocol),并将 xy 连接到每个结构体的水平和垂直分量,即 xdx 返回 CGVector(设置相同),xwidth 返回 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 CGVectorCGPoint 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 被使用是因为它明确要求 ==CGVectorCGPoint ,也许这优先于泛型。如果您知道为什么两个 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 替换 TU 得到:
func !=(lhs:CGPoint, rhs:CGPoint)->Bool

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

关于swift - '!=' 运算符的歧义使用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37816593/

10-12 06:48