我正在尝试编写一个泛型平均函数,它在包含数字类型的Iterable上运行.例如,它将在数组上运行,如下所示:
val rand = new scala.util.Random()
val a = Array.fill(1000) { rand.nextInt(101) }
val b = Array.fill(1000) { rand.nextDouble }
println(mean(a))
println(mean(b))
Run Code Online (Sandbox Code Playgroud)
希望能够处理其他迭代,例如列表.
我尝试了各种咒语的方法,但无济于事:
def mean[T <% Numeric[T]](xs: Iterable[T]) = xs.sum.toDouble / xs.size
def mean[A](xs: Iterable[Numeric[A]]):Double = xs.sum.toDouble / xs.size
def mean[T](xs: Iterable[T])(implicit num: Numeric[T]):Double = xs.sum / xs.size
def mean(xs: Iterable[Double]) = xs.sum / xs.size
Run Code Online (Sandbox Code Playgroud)
在Scala中执行此操作的正确方法是什么?
Dan*_*ral 17
这有效:
def mean[T : Numeric](xs: Iterable[T]): T = implicitly[Numeric[T]] match {
case num: Fractional[_] => import num._; xs.sum / fromInt(xs.size)
case num: Integral[_] => import num._; xs.sum / fromInt(xs.size)
case _ => sys.error("Undivisable numeric!")
}
Run Code Online (Sandbox Code Playgroud)
那么,让我们做一些解释.首先,Numeric必须在类型类模式中使用.也就是说,你没有说类型T是,或者可以转换成,Numeric.相反,Numeric提供一种类型的方法T.一个这样的例子是num.fromInt.
接下来,Numeric不提供通用的除法运算符.相反,必须在Fractional和之间做出选择Integral.在这里,我匹配Numeric[T]以区分两者.
请注意,我没有T在匹配上使用,因为Scala无法检查匹配上的类型参数,因为它们已被删除.相反,我使用_,如果可能的话,Scala会推断出正确的类型(就像在这里一样).
在那之后,我进口num._,其中num要么是Fractional或Integral.这会将一些隐式转换带入上下文,让我可以/直接调用方法.如果我不做那个导入,我会被迫写这个:
num.div(xs.sum, num.fromInt(xs.size))
Run Code Online (Sandbox Code Playgroud)
请注意,我不必将隐式参数传递给xs.sum,因为它已在范围中隐式可用.
我猜就是这样.我错过了什么吗?
你的一个版本非常接近:
def mean[T](xs: Iterable[T])(implicit num: Numeric[T]):Double =
num.toDouble(xs.sum) / xs.size
Run Code Online (Sandbox Code Playgroud)
这是另一种语法:
def mean[T: Numeric](xs: Iterable[T]):Double =
implicitly[Numeric[T]].toDouble(xs.sum) / xs.size
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2475 次 |
| 最近记录: |