Scala: неявное преобразование из общего типа во второй общий тип - программирование

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].

4b9b3361

Ответ 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]