Параметризация типов в Scala - PullRequest
4 голосов
/ 14 мая 2010

Итак, я сейчас изучаю Scala и пытаюсь создать абстрактный векторный класс с векторным пространством 3 (координаты x, y, z). Я пытаюсь добавить два из этих векторов вместе со следующим кодом:


package math

class Vector3[T](ax:T,ay:T,az:T) {
  def x = ax
  def y = ay
  def z = az
  override def toString = "&lt"+x+", "+y+", "+z+"&gt"
  def add(that: Vector3[T]) = new Vector3(x+that.x, y+that.y, z+that.z)
}

Проблема в том, что я получаю эту ошибку:

ошибка: несоответствие типов;
найдено: T
обязательно: String
def добавить (что: Vector3 [T]) = новый Vector3 (x + that.x, y + that.y, г + that.z)

Я пытался закомментировать вышеописанный метод "toString", но, похоже, это не имеет никакого эффекта. Может кто-нибудь сказать мне, что я делаю не так?

Ответы [ 4 ]

8 голосов
/ 16 мая 2010

Используя Scala 2.8, вы можете написать:

case class Vector3[T: Numeric](val x: T, val y: T, val z: T) {
  override def toString = "(%s, %s, %s)" format (x, y, z)

  def add(that: Vector3[T]) = new Vector3(
    plus(x, that.x),
    plus(y, that.y),
    plus(z, that.z)
  )

  private def plus(x: T, y: T) = implicitly[Numeric[T]] plus (x, y)
}

Позвольте мне объяснить. Во-первых, T: Numeric является границей контекста, которая неявно предоставляет экземпляр Numeric[T] вашему классу.

Черта Numeric[T] обеспечивает операции над числовыми типами,

trait Numeric[T] extends Ordering[T] {
  def plus(x: T, y: T): T
  def minus(x: T, y: T): T
  def times(x: T, y: T): T
  def negate(x: T): T
  // other operations omitted
}

Выражение implicitly[Numeric[T]] извлекает этот неявный контекст, так что вы можете выполнять такие операции, как plus, с вашими конкретными аргументами x, y и z, как показано в приватном методе выше.

Теперь вы можете создавать и add различные экземпляры Vector3, такие как Int и Double:

scala> Vector3(1,2,3) add Vector3(4,5,6)                                  
res1: Vector3[Int] = (5, 7, 9)

scala> Vector3(1.1, 2.2, 3.3) add Vector3(4.4, 5.5, 6.6)                      
res2: Vector3[Double] = (5.5, 7.7, 9.899999999999999)

Примечание: возможно использовать неявные преобразования для преобразования значений в Numeric[T].Ops экземпляры, чтобы вместо этого можно было написать следующее:

  def add(that: Vector3[T]) = new Vector3(x + that.x, y + that.y, z + that.z)

Я сознательно решил не использовать эти неявные преобразования, поскольку они (могут) понести некоторое снижение производительности, создав временные объекты-оболочки. Фактическое влияние на производительность зависит от JVM (например, в какой степени он поддерживает escape-анализ, чтобы избежать фактического размещения объектов в куче). Использование привязки к контексту и implicitly позволяет избежать потенциальных затрат ... за счет некоторого многословия.

8 голосов
/ 14 мая 2010

Вы не ограничивали параметр типа T, поэтому компилятор возвращается к интерпретации + как конкатенации строк.

6 голосов
/ 14 мая 2010

Проблема T. Он имеет тип Any, но Any не имеет оператора +. Ошибка в String - ошибка. Таким образом, вам нужно определить min, связанный с типом, который делает.

4 голосов
/ 16 мая 2010

Оба ответа от @sblundy и @Randall Schulz, конечно, верны, но если вам нужен более конкретный совет о том, как ограничить T, тогда как насчет:

class Vector3[T <% Double](ax:T,ay:T,az:T) {
...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...