【问题标题】:Scala Generics and Numeric ImplicitsScala 泛型和数值隐式
【发布时间】:2011-10-14 09:49:28
【问题描述】:

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

下面的例子解释了这个问题。

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]) {

和其他几种组合,但我最终得到了

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

【问题讨论】:

    标签: generics scala numeric implicit


    【解决方案1】:

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

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

    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 类型可以转换为A 已知的某种类型Numeric[A]。 创建实例时,您必须始终提供所有类型参数,因为它们无法推断。

    如果您不需要 sum 保持稳定,您可以将您的课程更改为:

    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]
    

    但在加宽时,您仍然需要提供类型信息。

    【讨论】:

    • 您的第一个解决方案有效吗?编译器会抱怨 b.value 应该是一个字符串。
    • @Moritz,虽然您的第二个建议有效,但我仍然有义务在它们不同时插入类型。这行不通,因为我将来不知道算术会出现什么类型。它应该是自动的,就像你在 REPL 中写 2 + 4.1 并得到 6.1 一样。
    • @Moritz,至于您的第一个建议,我也无法使其发挥作用。错误:不明确的隐式值:对象 scala.math.Numeric.BigIntIsIntegral 类型的对象 Numeric 中的对象 BigIntIsIntegral 和对象 scala.math.Numeric.IntIsIntegral 类型的对象 Numeric 中的对象 IntIsIntegral 匹配预期类型 Numeric[A] val a = new算术(n1.value, n5.value),其中 n1 和 n5 是常数。
    • @HugoSFerreira, @tiagoboldt:如果您使用第一个示例,则必须在构造实例时提供 all 类型参数,例如:new Arithmetic[Double,Int,Double](intConn, dblConn),因为它们无法推断.
    • @HugoSFerreira 你忘了import Numeric.Implicits._吗?
    猜你喜欢
    • 2021-08-25
    • 1970-01-01
    • 2018-11-21
    • 1970-01-01
    • 2011-09-12
    • 1970-01-01
    • 2020-02-11
    • 1970-01-01
    • 2020-10-12
    相关资源
    最近更新 更多