在Scala中指定Generic的子类型

时间:2011-10-10 14:29:52

标签: generics scala variance

考虑下面的例子,它应该打印8.为什么A.Value + B.Value认为B.Value应该是一个字符串?我该如何解决?

object Catano extends App {
  val const3 = new Constant(3)
  val const5 = new Constant(5)

  val block = new Arithmetic(const3.Result, const5.Result)

  println(block.Sum.Value)
}

class Block

class Arithmetic[T: Numeric](val A: Connector[T], val B: Connector[T]) extends Block {
  def Sum = new Connector({ A.Value + B.Value })
}

class Constant[T](x: T) extends Block {
  def Result = new Connector({ x })
}

class Connector[T](f: => T) {
  def Value: T = f
}

出于类型安全原因,以下内容应该因类型异常而失败:

  val const3 = new Constant("ping")
  val const5 = new Constant("pong")

  val block = new Arithmetic(const3.Result, const5.Result)

2 个答案:

答案 0 :(得分:6)

您的问题可以通过以下方式重现:

class C[T: Numeric] {def add(a: T, b: T) = a+b }
error: type mismatch;
found   : T
required: String

那里发生了什么:在java中的scala中,你可以做String +任何东西,也可以做任何事情+ String。因为,与java不同,pperators只是普通的方法调用,这似乎意味着每种类型都有相应的+方法。当然,事实并非如此,因为java类型没有这样的方法。我们所拥有的是implicit def any2StringAdd(x: Any) Predef,它通过隐式转换使+可用。在您的代码中,这是唯一的+可用,这就是为什么抱怨B.Value不是String

现在为什么预定的+不可用? T:Numeric要求隐式范围中存在Numeric[T]值。它没有提到T应该是什么类型,以及T上可用的方法。此Numeric[T]实例具有def plus(x: T, y: T): T方法。单凭这一点并不会使T上有+。你可以直接调用加号,但这不方便。幸运的是,+委派plus可以通过隐式转换添加(就像+(String)中的Predef一样),前提是您在范围内添加了一些含义:

import Numeric.Implicits._

答案 1 :(得分:0)

这有效:

class Arithmetic[ T <: Int] (val A: Connector[T], val B: Connector[T]) extends Block {
  def Sum = new Connector({ A.Value + B.Value })
}

数字没有+功能