如何扩展 List[Double]

how to extend List[Double]

我想要一个在功能上扩展 List[Double] 并增加一些功能的自定义 class。我对 Pimp My Library 的理解会引导我构建如下内容:

implicit class MahThing(list:List[Double]) {
    def mahStuff = ...
}

问题是,现在到处都导入 MahThing,所有 List[Double] 都可以选择 mahStuff

同上:

class MahThing(list:List[Double]) {
    def mahStuff ...
}
implicit def toThing(list:List[Double]) = new MahThing(list)

现在,list.toThing 生产 MahThing,但 MahThing 不能做 Listy 东西。煞费苦心地将 MahThing 中的 List 操作定义为 list.operation 是很费力的。出于某种原因,使用 MahThing 的实例,它让我例如在 map 操作期间声明变量类型。

我真正需要的是扩展 List[Double] 的确切功能。本该 MahThing 的事情却 mahStuff 去做了,而没有其他人去做。另外,MahThing 在其他方面都和 List 一样。

使用隐式转换是扩展 List[T](在你的情况下 T 是 Double)功能的正确方法(作为 List[T] final,它不能被扩展)并且如你所见

everywhere MahThing is imported, all List[Double]s have the option to do mahStuff.

但是,如果我没弄错的话,你不希望所有的 List[Double] 都像那样,所以我的建议是创建一个 MahDouble class 来接受 Double 作为参数并将两种方式隐式转换为 Double

object MahDouble {
   implicit def toMah(d: Double): MahDouble = new MahDouble(d)
   implicit def backToDouble(m: MahDouble): Double = m.d
}

case class MahDouble(d: Double)

然后您可以将该 MahDouble 用作您的 MahThing List 的类型,并将其从 List[MahDouble] 隐式转换。

object MahThing {
   implicit def toThing(list:List[MahDouble]): MahThing = new MahThing(list)
}

case class MahThing(list:List[MahDouble]) {
   def mahStuff ...
}

对于任何 aspect MahDouble 都将作为 Double,但只有由 MahDouble 元素组成的列表才会获得 mahStuff 方法

val mahDoubleList: List[MahDouble] = List(2.0, 3.0, 4.0, 5.0)

此致, 亚历山德罗.

正如@Alessandro G. 建议的那样,最好的方法是为 MahDouble 创建特殊类型 - 而不是整个 List:

case class MahDouble(d: Double) extends AnyVal

extends AnyVal 会给你 value class 以避免开销。

但是,我不建议您在 MahDoubleDouble 之间进行隐式转换,因为它太不可预测并且非常难以理解正在发生的事情,请参阅 this article

但是您仍然可以为您的特殊双打添加漂亮的构造函数:

 implicit class RichDouble(d: Double){
    def mah = MahDouble(d)
 }

这是你的列表类型class:

 implicit class RichMaxDoubleList(l: List[MahDouble]){
    def mahStuff = "done"
 }

现在您可以使用它了:

 scala> val l = List(1.0 mah, 2.0 mah)
 l: List[MahDouble] = List(MahDouble(1.0), MahDouble(2.0))

 scala> l.mahStuff
 res7: String = done

您也可以将常规列表转换为 mah 列表并返回:

scala> List(1.0, 2.0).map(_.mah)
res8: List[MahDouble] = List(MahDouble(1.0), MahDouble(2.0))

scala> res8.map(_.d)
res9: List[Double] = List(1.0, 2.0)

以下是我对隐式转换的看法。首先,隐式 class:

implicit class MahThing(val list: List[Double]) {
   def mahStuff = {
     // ...do your checks
     this // to ensure we get the object back so I can chain list-like functions off it to prove it has been converted back.
   }
}

和反向隐式 def 以转换回列表:

implicit def thing2list(thing: MahThing): List[Double] = thing.list

应用于双精度列表:

scala> dbs.mahStuff
res1: MahThing = MahThing@35e06c5d

scala> dbs.mahStuff.tail
res2: List[Double] = List(0.45)

对 tail 的调用表明 MahStuff 实例很容易转换回列表。

现在尝试使用字符串列表:

scala> val strs = "foo" :: "bar" :: Nil
strs: List[String] = List(foo, bar)

scala> strs.mahStuff
<console>:13: error: value mahStuff is not a member of List[String]
              strs.mahStuff
                   ^

显示其他列表类型未转换。