Подтвердить что ты не робот

Почему в вспомогательных конструкторах Scala допустимы параметры типа?

Скажем, я определяю простой 2D-класс в Scala, и я хочу иметь возможность его создавать с помощью различных типов:

class Point(x:Float, y:Float) {
    this(x:Double, y:Double) = this(x.toFloat, y.toFloat)
    this(x:Int, y:Int) = this(x.toFloat, y.toFloat)
    // etc...
}

Я хочу сварить это с помощью шаблона, например:

class Point(x:Float, y:Float) {
    this[T](x:T, y:T) = this(x.toFloat, y.toFloat)
}

Я знаю, что это не сработает, так как T может быть типом, для которого toFloat не определен, но ошибка компилятора, которую я получаю:

здесь не разрешены параметры типа

Это просто не поддерживается в Scala? Если да, то почему, и есть ли простой способ обойти это?

4b9b3361

Ответ 1

Scala Конструкторы классов (в отличие от Java) не могут принимать параметры типа, только сам класс. Что касается того, почему Scala сделал этот выбор дизайна, я предполагаю, что основной причиной является простота.

Если вам нужен вторичный метод "строитель", который является общим, естественным является определение его на сопутствующем объекте. Например,

object Point {
  def build[T : Numeric](x: T, y: T) = {
    val n = implicitly[Numeric[T]]
    new Point(n.toFloat(x), n.toFloat(y))
  }
}

class Point(val x:Float, val y:Float)

val p = Point.build(1, 2) // Companion object builder
p.x + p.y

Здесь я использовал класс Numeric для получения общего метода toFloat.

Ответ 2

Я играл с этим некоторое время, становясь "закрытым", как...

class Point(x:Float, y:Float) {
  def this[T <: Any { def toFloat: Float }](x:T, y:T) = this(x.toFloat, y.toFloat)
}

..., что приводит к ошибке: здесь не допускаются параметры типа (как и в столбце), а затем я понял...

Если инициализатор может принимать параметры типа, он будет неоднозначным с параметрами класса, если таковые имеются. Не то, чтобы это не сработало в спецификации языка... но это, по крайней мере, более сложный случай. Также могут возникать проблемы совместимости с Java.

Представьте себе:

class Foo[T](x: T) {
   def this[X](z: X) = ...
}
new Foo[Int](42) // T is Int? X is ...? Or ...?

Лично я желаю, чтобы Scala следовал за Eiffel-подобным шаблоном (только с именем constructors или "factory methods" ), но, увы, это не было бы Scala.

Счастливое кодирование.