Specifying the subtype of a Generic in Scala
Consider the following example, which should print 8. Why does the A.Value + B.Value
thinks that B.Value
should be a string? How do I fix it?
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
}
开发者_运维百科
For type-safety reasons, the following should fail with a Type exception:
val const3 = new Constant("ping")
val const5 = new Constant("pong")
val block = new Arithmetic(const3.Result, const5.Result)
Your problem can be reproduced with just:
class C[T: Numeric] {def add(a: T, b: T) = a+b }
error: type mismatch;
found : T
required: String
What is happening there : in scala as in java, you can do String + anything, and also anything + String. As, unlike in java, pperators are just normal method calls, that seems to imply there is a corresponding + method on each type. Of course, it is not so, as java types have no such method. What we have is implicit def any2StringAdd(x: Any)
in Predef
, which makes this +
available by implicit conversion. In your code, this is the only + available, which is why it complains B.Value
is not a String
.
Now why is the intended +
not available? T:Numeric
requires that there is a Numeric[T]
value in implicit scope. It says nothing about what type T should be, and what methods are available on T
. This Numeric[T]
instance has a def plus(x: T, y: T): T
method. That alone does not make +
available on T. You can call plus directly, but this is not covenient. Fortunately, a +
delegating to plus
can be added by implicit conversion (just like the +(String)
was in Predef
), provided you put some implicits in scope with :
import Numeric.Implicits._
This works:
class Arithmetic[ T <: Int] (val A: Connector[T], val B: Connector[T]) extends Block {
def Sum = new Connector({ A.Value + B.Value })
}
Numeric doesn't have a +
function
精彩评论