首页 文章

Scala优先考虑隐式转换而不是“自然”操作......为什么?这是一个错误吗?或者我做错了什么?

提问于
浏览
9

当然,这个简单的测试按预期工作:

scala> var b = 2
b: Int = 2

scala> b += 1   

scala> b
res3: Int = 3

现在我将其纳入范围:

class A(var x: Int) { def +=(y:Int) { this.x += y } }
implicit def int2A(i:Int) : A = new A(i)

我正在为它定义一个新类和一个=操作,并且当我想要将Int添加到A的Int值时,这是一个方便的隐式转换 .

当“A”类不是表达式的所有部分时,我从未预料到这会影响我的常规Int操作的行为方式 .

但它确实:

scala> var b:Int = 0
b: Int = 0

scala> b += 1

scala> b  
res29: Int = 0

scala> b += 2

scala> b
res31: Int = 0

这里似乎发生的是b:Int被隐式转换为“A”,它不绑定到任何变量,然后在其上调用=,丢弃结果 .

Scala似乎高度优先于已经定义为Ints的自然=行为(编译器魔法,而不是实际方法)的隐式转换 . 常识以及C背景告诉我,只有当编译失败时才应该作为最后的手段调用implicits . 这导致了几个问题......

  • 为什么?这是一个错误吗?它是按设计的吗?

  • 是否有解决办法(除了不使用"+="用于我的DSL的"+="操作)?

谢谢

5 回答

  • 6

    即使遭到Eastsun的解释,似乎这是一个错误,它应该在尝试 += 的隐式转换之前尝试 b=b+1 转换 .

    请通过发送电子邮件至scala-user@listes.epfl.ch或访问n4.nabble.com/Scala-User-f1934582.html,将此问题提交给scala用户电子邮件列表 . 如果它是一个错误,那就是它会被注意到并修复的地方 .

  • 3

    正如其他人所说,Int不能有一个=“方法”,因为Int是不可变的 . 相反,x = 1被视为x = x 1的短格式,但前提是没有在类型上定义的名为=的方法 . 因此方法解析优先 .

    鉴于Scala允许您定义=方法并且还允许您对变量执行=,我们是否可以更改两者的优先级?即尝试扩展=第一次,只有当它失败时才搜索名为=的方法?

    理论上是的,但我认为它会比现在的方案更糟糕 . 实际上,没有 . Scala的集合库中有许多类型,它们既定义了非破坏性添加的方法,又定义了用于破坏性添加的方法 . 如果我们已经切换了优先权,那么就像是

    myHashTable += elem
    

    会扩大到

    myHashTable = myHashTable + elem
    

    因此,它将构造一个新的哈希表并将其分配给变量,而不是简单地更新元素 . 不是明智之举......

  • 1

    从Scala编程,第17章:

    每当你写a = b,并且a不支持名为=的方法时,Scala会尝试将其解释为a = a b .

    Int不包含方法 += . 但是 A 类提供了 += 方法 . 这可能会触发从 IntA 的隐式转换 .

  • 13

    我不认为这是一个错误 . 实际上,Int只有一个“”方法,但没有“=”方法 . 如果不存在具有“=”方法的其他隐式,则b = 1将在编译时转换为b = b 1 .

  • 1

    Scala似乎优先于对已经定义为Ints的自然=的隐式转换 .

    您在谈论哪个版本的Scala?我不知道 Int 上有 += 方法的任何版本 . 当然,没有一个仍然支持的版本,你必须有一些非常古老的版本 .

    由于 Int 上没有 += ,但是您在 Int 上调用了 += 方法,因此Scala尝试通过隐式转换来满足该类型约束 .

相关问题