为什么隐式搜索会受到不相关类型参数的影响?

发布于 2025-01-02 06:05:51 字数 1720 浏览 1 评论 0原文

考虑 Scala 中一些测量单位功能的简化片段:

object UnitsEx {
  case class Quantity[M <: MInt, T: Numeric](value: T) {
    private val num = implicitly[Numeric[T]]
    def *[M2 <: MInt](m: Quantity[M2, T]) = 
      Quantity[M, T](num.times(value, m.value))
  }

  implicit def measure[T: Numeric](v: T): Quantity[_0, T] = Quantity[_0, T](v)
  implicit def numericToQuantity[T: Numeric](v: T): QuantityConstructor[T] = 
    new QuantityConstructor[T](v)

  class QuantityConstructor[T: Numeric](v: T) {
    def m = Quantity[_1, T](v)
  }

  sealed trait MInt
  final class _0 extends MInt
  final class _1 extends MInt
}

此片段显示了我当前得到的用法和编译器错误:

import UnitsEx._

(1 m) * 1 // Works
1 * (1 m) // Doesn't work:
/*
<console>:1: error: overloaded method value * with alternatives:
(x: Double)Double <and>
(x: Float)Float <and>
(x: Long)Long <and>
(x: Int)Int <and>
(x: Char)Int <and>
(x: Short)Int <and>
(x: Byte)Int
cannot be applied to (UnitsEx.Quantity[UnitsEx._1,Int])
1 * (1 m)
^
*/

measure 包装 1 可以解决问题,但为什么不应用隐式范围?

如果我像下一个代码片段一样删除类型参数 M ,它就会开始工作,尽管我看不到该类型参数与隐式搜索有何关系:

object UnitsEx2 {   
  case class Quantity[T: Numeric](value: T) {
    private val num = implicitly[Numeric[T]]
    def *(m: Quantity[T]) = Quantity[T](num.times(value, m.value))
  }

  implicit def measure[T: Numeric](v: T): Quantity[T] = Quantity[T](v)
  implicit def numericToQuantity[T: Numeric](v: T): QuantityConstructor[T] = 
    new QuantityConstructor[T](v)

  class QuantityConstructor[T: Numeric](v: T) {
    def m = Quantity[T](v)
  }
}

这是预期的还是类型检查器的已知限制?

Consider this simplified snippet of some units of measurement functionality in Scala:

object UnitsEx {
  case class Quantity[M <: MInt, T: Numeric](value: T) {
    private val num = implicitly[Numeric[T]]
    def *[M2 <: MInt](m: Quantity[M2, T]) = 
      Quantity[M, T](num.times(value, m.value))
  }

  implicit def measure[T: Numeric](v: T): Quantity[_0, T] = Quantity[_0, T](v)
  implicit def numericToQuantity[T: Numeric](v: T): QuantityConstructor[T] = 
    new QuantityConstructor[T](v)

  class QuantityConstructor[T: Numeric](v: T) {
    def m = Quantity[_1, T](v)
  }

  sealed trait MInt
  final class _0 extends MInt
  final class _1 extends MInt
}

This snippet shows the usage and the compiler error I get currently:

import UnitsEx._

(1 m) * 1 // Works
1 * (1 m) // Doesn't work:
/*
<console>:1: error: overloaded method value * with alternatives:
(x: Double)Double <and>
(x: Float)Float <and>
(x: Long)Long <and>
(x: Int)Int <and>
(x: Char)Int <and>
(x: Short)Int <and>
(x: Byte)Int
cannot be applied to (UnitsEx.Quantity[UnitsEx._1,Int])
1 * (1 m)
^
*/

Wrapping the 1 with measure would fix the problem, but why isn't the implicit in scope applied?

If I remove the type parameter M like in the next snippet it starts working, although I can't see how that type parameter is related to implicit search:

object UnitsEx2 {   
  case class Quantity[T: Numeric](value: T) {
    private val num = implicitly[Numeric[T]]
    def *(m: Quantity[T]) = Quantity[T](num.times(value, m.value))
  }

  implicit def measure[T: Numeric](v: T): Quantity[T] = Quantity[T](v)
  implicit def numericToQuantity[T: Numeric](v: T): QuantityConstructor[T] = 
    new QuantityConstructor[T](v)

  class QuantityConstructor[T: Numeric](v: T) {
    def m = Quantity[T](v)
  }
}

Is this expected or a known limitation of the type checker?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

兔小萌 2025-01-09 06:05:51

如果将 * 运算符重命名为 mult,则 1 mult (1 m) 在这两种情况下都适用。
这并没有回答您的问题,但确实暗示了可能对重载的 * 运算符存在一些干扰。

If you rename the * operator to e.g. mult then 1 mult (1 m) works in both cases.
This does not answer your question but does hint in the direction that perhaps there is some interference with the heavily overloaded * operator.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文