Указание подтипа универсального в Scala - PullRequest
1 голос
/ 10 октября 2011

Рассмотрим следующий пример, который должен вывести 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 ]

6 голосов
/ 10 октября 2011

Ваша проблема может быть воспроизведена с помощью:

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

Что там происходит: в scala, как и в java, вы можете делать 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._
0 голосов
/ 10 октября 2011

Это работает:

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

Числовой не имеет функции +

...