我正在尝试编写一个泛型平均函数,它在包含数字类型的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 次 |
最近记录: |