Почему в вспомогательных конструкторах 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? Если да, то почему, и есть ли простой способ обойти это?
Ответы
Ответ 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.
Счастливое кодирование.