开发者

Specifying the subtype of a Generic in Scala

开发者 https://www.devze.com 2023-04-11 19:31 出处:网络
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?

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

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号