Scala泛型和数字隐含 [英] Scala Generics and Numeric Implicits

查看:120
本文介绍了Scala泛型和数字隐含的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要将两个函数作为参数传递给scala函数.然后,该函数应评估它们并从中获取一个数字,然后对其进行运算.该数字可以是Int,Double或任何其他数字类型.我希望函数能够正常工作,无论它正在使用什么类型.

I need to pass two functions as parameters to a scala function. That function should then evaluate them and get a number from them where it will then operate on. This number can be either a Int, Double or any other numeric type. I would like the function to work, whatever the types it is working with.

下面的示例说明了该问题.

The example bellow explains the issue.

import Numeric.Implicits._

class Arithmetic[T : Numeric](val A: Connector[T], val B: Connector[T]) {
  val sum  = new Connector({ A.value + B.value })
}

class Constant[T](var x: T) {
  val value = new Connector({ x })
}

class Connector[T](f: => T) {
  def value: T = f
  override def toString = value.toString()
}

object Main extends App{
  val n1 = new Constant(1)

  // works
  val n5 = new Constant(5)
  val a = new Arithmetic( n1.value, n5.value )
  println(a.sum)

 // no works
 val n55 = new Constant(5.5)
 val b = new Arithmetic( n1.value, n55.value )
 println(b.sum)

}

我也尝试过

class Arithmetic[T,R : Numeric](val A: Connector[T], val B: Connector[R]) {

和其他几种组合,但最终还是

and several other combinations, but I ended up with

error: could not find implicit value for parameter num: scala.math.Numeric[Any]
val sum  = new Connector({ A.value + B.value })

推荐答案

您看到的错误消息是因为Numeric[T].plus只能用于添加两个相同类型的值 T . 您的代码是在假设数字会自动发生扩展的情况下编写的-在这种情况下,由于存在Numeric[T]实例,编译器对类型一无所知,所以不会这样做.

The error message you are seeing is because Numeric[T].plus can only be used to add two values of the same type T. Your code is written under the assumption that numeric widening happens automatically - which will not in this case as the compiler does not know anything about the types except that there exists a Numeric[T] instance.

如果需要sum作为稳定值,则必须在构造函数中提供必要的类型信息,如下所示:

If you need sum to be a stable value, you will have to provide the necessary type information in the constructor like this:

class Arithmetic[A : Numeric, R <% A, S <% A](val a: Connector[R], b: Connector[S]) {
  val sum = new Connector[A]((a.value:A) + (b.value:A))
}

这要求将RS类型转换为已知Numeric[A]距离的某些A类型. 创建实例时,您将始终必须提供所有类型参数,因为无法推断出它们.

This requires types R and S to be convertible into some type A for which a Numeric[A] istance is known. When creating an instance you would always have to provide all type parameters as they cannot be inferred.

如果您不需要sum来稳定,则可以将您的班级更改为此:

If you do not need sum to be stable you could change your class to this:

class Arithmetic[A,B](val a: Connector[A], val b: Connector[B]) {

  // if A and B are the same types
  def sum(implicit e: B =:= A, n: Numeric[A]): Connector[A] =
    new Connector(n.plus(a.value, b.value))

  // else widen to C
  def wideSum[C](implicit f: A => C, g: B => C, n: Numeric[C]) =
    new Connector(n.plus(a.value, b.value))
}

val a = new Connector(1)

val b = new Connector(2)

val c = new Connector(3.0)

val d = (new Arithmetic(a,b)).sum

// val e = (new Arithmetic(b,c)).sum // <-- does not compile

val e = (new Arithmetic(b,c)).wideSum[Double]

扩展时,您仍然必须提供类型信息.

When widening you will still have to provide the type information though.

这篇关于Scala泛型和数字隐含的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆