【问题标题】:Ambiguous use of '!=' operator'!=' 运算符的不明确使用
【发布时间】:2016-06-14 15:44:09
【问题描述】:

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

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

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

当然,我扩展了 3 个结构以符合协议并将xy 连接到每个结构的水平和垂直组件,即x 返回dxCGVector(设置相同),xCGSize 返回 width ,而 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

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

对我来说这似乎是一个编译器错误,但我不确定,我尝试清理项目、重新启动 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,并且可能优先于泛型。不确定如果您知道为什么两个 == 运算符不冲突,请告诉我。

【问题讨论】:

  • 如果您不覆盖!= 定义会发生什么?它有一个基于not == 的默认实现
  • 顺便说一句,不要为您自己的类型使用 CG 前缀。它通常为 CoreGraphics 保留
  • 好吧,我想我可以这样做,但感觉不对,我需要手动比较这是我想要避免的,但如果找不到另一个解决方案是我要走的路。是的,我在考虑 CG 的东西,我会改变它,这只是我命名它时想到的第一件事。
  • “我需要手动比较”嗯?
  • 现在我明白了,你的意思是像使用!(aVector == anotherVector),我想应该不会那么糟糕

标签: swift operator-overloading core-graphics ambiguous


【解决方案1】:

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

(其实如果你看Equatableprotocol requirements唯一需要的函数就是func ==

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

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

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

更新

您没有使用可等式类型。问一个点是否等于一个大小是没有意义的。你的问题源于试图强迫它有意义。

您正在为每种类型组合提供一个相等运算符。因此,您提供了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)-&gt;Bool

当你说CGPoint()==CGVector() 时,它会寻找func ==(lhs:CGPoint, rhs:CGVector)-&gt;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)-&gt;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

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

【讨论】:

  • 是的,我不知道 != 运算符不是必需的。无论如何,我尝试不定义它但仍然没有工作,显然它是模棱两可的,因为两种重载(核心图形中的一个和它从 equatable 获得的一个)都可以使用并且编译器会感到困惑,而不是 = = 运算符出于某种原因,无论如何请阅读更新,看看你是否知道为什么会这样。虽然我解决了将它们全部转换为 vector_float2 并使用该类型的运算符
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多