Scala: неявное преобразование из общего типа во второй общий тип
Скажем, у меня есть два набора классов, и первый набор наследует от Foo, а второй набор наследует от Bar.
class Foo
class Baz extends Foo
class Bar
class Qux extends Bar
Я хочу создать общую неявную функцию преобразования, которая преобразует любой Foo в Bar, если в области есть неявный тип конвертера.
trait Converter[A <: Foo, B <: Bar] {
def convert(a : A) : B
}
implicit object BazToQuxConverter extends Converter[Baz, Qux] {
def convert(a : Baz) : Qux = new Qux
}
implicit def FooToBar[A <: Foo, B <: Bar](a : A)(implicit converter : Converter[A, B]) : B = converter.convert(a)
К сожалению, это не работает, как я ожидал. Когда я подключу следующие строки к REPL:
val a : Baz = new Baz
val b : Qux = a
... Я получаю следующую ошибку:
<console>:17: error: type mismatch;
found : Baz
required: Qux
val b : Qux = a
^
Есть ли способ заставить это работать? Ближайшим, к которому я пришел, является следующее:
implicit def BadFooToBar[A <: Foo, B <: Bar](a : A)(implicit converter : Converter[A, _]) : B = converter.convert(a).asInstanceOf[B]
Это работает для моего предыдущего примера, но это не очень безопасно.
class Qax extends Bar
val a : Baz = new Baz
val b : Qax = a
Это будет скомпилировано просто отлично, но оно будет взорваться во время выполнения, потому что Qux
(результат converter.convert(a)
) нельзя отнести к Qax
(asInstanceOf[Qax]
). В идеале я хочу, чтобы эта строка была поймана во время компиляции, так как в области не существует Converter[Bax,Qax]
.
Ответы
Ответ 1
Это ошибка, которая исправлена в 2.11. Похоже, что он исправлен с PR 2822, соответствующий билет SI-3346.
Welcome to Scala version 2.11.0-20131030-090728-c38235fd44 (OpenJDK 64-Bit Server VM, Java 1.7.0_45).
Type in expressions to have them evaluated.
Type :help for more information.
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Foo
class Baz extends Foo
class Bar
class Qux extends Bar
trait Converter[A <: Foo, B <: Bar] {
def convert(a : A) : B
}
implicit object BazToQuxConverter extends Converter[Baz, Qux] {
def convert(a : Baz) : Qux = new Qux
}
import scala.language.implicitConversions
implicit def FooToBar[A <: Foo, B <: Bar](a : A)(implicit converter : Converter[A, B]) : B = converter.convert(a)
val a : Baz = new Baz
val b : Qux = a
// Exiting paste mode, now interpreting.
defined class Foo
defined class Baz
defined class Bar
defined class Qux
defined trait Converter
defined object BazToQuxConverter
import scala.language.implicitConversions
FooToBar: [A <: Foo, B <: Bar](a: A)(implicit converter: Converter[A,B])B
a: Baz = [email protected]
b: Qux = [email protected]