Работает:
trait Transformer[A, B] {
def transform(a: A): B
}
class TransformerImpl extends Transformer[Int, String] {
override def transform(value: Int): String = {
value.toString
}
}
Это то, что я хочу, потому что черта с одним параметром проще и потому что конкретное значение B определяется A. Однако это не работает.
trait Transformer2[A] {
def transform[B](a: A): B
}
class Transformer2Impl extends Transformer2[Int] {
override def transform[String](value: Int): String = {
value.toString
}
}
Ошибка:
-- [E007] Type Mismatch Error: --------
3 | value.toString
| ^^^^^^^^^^^^^^
| Found: String
| Required: String
Это тоже с другой сигнатурой метода не работает:
class Transformer2IntToIntImpl extends Transformer2[Int] {
override def transform(value: Int): Int = {
value
}
}
Ошибка:
-- Error: ----------------------------------------------------------------------
1 |class Transformer2IntToIntImpl extends Transformer2[Int] {
| ^
|class Transformer2IntToIntImpl needs to be abstract, since def transform[B](a: A): B in trait Transformer2 is not defined
|(Note that
| parameter A in def transform[B](a: A): B in trait Transformer2 does not match
| parameter Int in override def transform(value: Int): Int in class Transformer2IntToIntImpl
| )
-- [E038] Declaration Error: ---------------------------------------------------
2 | override def transform(value: Int): Int = {
| ^
|method transform has a different signature than the overridden declaration
|-----------------------------------------------------------------------------
2 errors found
Судя по ошибкам, я попробовал несколько альтернатив, но безуспешно.
Это сработало для меня:
trait Transformer2[A] {
type B
def transform(a: A): B
}
class Transformer2Impl extends Transformer2[Int] {
type B = String
override def transform(value: Int): String = {
value.toString
}
}
class Transformer2IntToIntImpl extends Transformer2[Int] {
type B = Int
override def transform(value: Int): Int = {
value
}
}
val ans1 = new Transformer2Impl().transform(5)
// val ans1: String = 5
val ans2 = new Transformer2IntToIntImpl().transform(5)
// val ans2: Int = 5
Мне все равно хотелось бы знать, произошел ли сбой в исходном коде (хотя и с запутанными сообщениями об ошибках), потому что он синтаксически неверен.
Это не синтаксически неверно, это семантически неверно.
Определения
// (1)
trait Transformer[A, B] {
def transform(a: A): B
}
или
// (2)
trait Transformer2[A] {
type B
def transform(a: A): B
}
означает, что реализация (для фиксированного A
, B
) Transformer
знает, как преобразовать это фиксированное A
в это фиксированное B
.
О (1) и (2) см.
Scala: абстрактные типы против дженериков ( ответ)
Абстрактные типы и параметры типа
Это определение
// (3)
trait Transformer2[A] {
def transform[B](a: A): B
}
означает нечто иное. А именно, его реализация (для фиксированного A
) умеет преобразовать этот фиксированный A
в произвольный B
.
потому что конкретное значение
B
определяетсяA
Это (2), а не (3).
Здесь
// (4)
class Transformer2Impl extends Transformer2[Int] {
override def transform[String](value: Int): String = {
value.toString
}
}
String
в [String]
не является стандартным java.lang.String
(он же scala.Predef.String
). Вы не указываете B
. На самом деле вы определяете новый параметр типа, обозначаемый String
, и этот новый тип затеняет стандарт String
. Не имеет значения, как обозначить параметр типа. Итак, (4)
точно такой же, как
// (5)
class Transformer2Impl extends Transformer2[Int] {
override def transform[B](value: Int): B = {
value.toString
}
}
Вот почему ошибка компиляции.
Лучше включить scalacOptions += "-Xlint:type-parameter-shadow"
, тогда в такой ситуации вы получите предупреждение.
Здесь
// (6)
class Transformer2IntToIntImpl extends Transformer2[Int] {
override def transform(value: Int): Int = {
value
}
}
вы явно изменили подпись, поэтому ошибка компиляции.
Как правило, любая функция с сигнатурой
f[A](...): A
, не имеющаяA
на входе, должна выбрасывать/расходиться. В частности,def transform[Str](value: Int): Str
должен бросить/разойтись.