为scala中的类使用Numeric类型边界的正确方法



一般问题:定义类型为Numeric的泛型类的正确方法是什么,最好不要在Scala 2中使用任何implicit

具体示例:考虑以下围绕Integer序列构建的玩具类:

class NewList(val values: Seq[Int]) {
def +(x: Int): NewList = new NewList(values.map(_ + x))
}
val x = new NewList(List(1,2,3))
(x + 5).values  // ---> List(6, 7, 8)

现在假设我们想使NewList通用,围绕任何数字序列:

// Would not compile
class NewList[T: Numeric](val values: Seq[T]) {
def +(x: T): NewList = new NewList(values.map(_ + x))
}

由于某种奇怪的类型不匹配,上面的代码无法编译

cmd2.sc:2: type mismatch;
found   : T
required: String
def +(x: T): NewList[T] = new NewList(values.map(_ + x))
^Compilation Failed
Compilation Failed

据我所知,这个编译错误显然意味着编译器无法将变量x: T解析为Numeric类型,因此无法解析plus的参数类型。尝试在类定义或方法定义中声明+(x: Numeric[T])或使用(implicit num: T => Numeric[T])将没有帮助。

使类按预期编译和行为的唯一方法是使用implicitly[Numeric[T]]:的plus方法

class NewList[T: Numeric](val values: Seq[T]) {
def +(x: T): NewList[T] = new NewList(values.map(implicitly[Numeric[T]].plus(_, x)))
}
val x = new NewList(List(1,2,3))
(x + 5).values  // ---> List(6, 7, 8)
  • 为什么编译器不能为T解析方法plus,即使它在类定义中被声明为Numeric
  • 有没有更好的方法来解决这个问题,而不使用丑陋的样板implicitly[Numeric[T]].plus
  • 一般来说,我们可以避免implicit在scala中处理此类情况吗

为什么编译器不能解析t的方法加号,即使它在类定义中声明为Numeric?

首先,因为T不是Numeric;相反,它有一个Numeric类型类的实例与其关联
其次,即使TNumeric,它也不会有+方法;因为,类型类不是这样工作的
检查此项:https://gist.github.com/BalmungSan/c19557030181c0dc36533f3de7d7abf4

有没有更好的方法来解决这个问题,而不使用隐式的丑陋样板[Numeric[T]].plus?

是的,只需在顶层或class或方法内部导入扩展方法:import Numeric.Implicits._

我们通常可以避免隐式来处理scala中的此类情况吗?

[T: Numeric]只是(implicit ev: Numeric[T])的糖语法,所以不,您无法避免implicits

这很好,真的。

最新更新