Классы типов и подтипы - PullRequest
1 голос
/ 20 марта 2012

У меня есть следующий код, определяющий класс типов.

trait Foo[T] {
  def toFoo(x: T): String
}

trait Foos {
  def toFoo[T](f: T => String): Foo[T] = new Foo[T] {
    def toFoo(x: T): String = f(x)
  }
}

object Foo extends Foos {
  def toFoo[A: Foo](a: A) = implicitly[Foo[A]].toFoo(a)
  implicit def AToFoo: Foo[A] = toFoo { c =>
    "A"
   }
  implicit def BToFoo[T]: Foo[B] = toFoo { c  => 
    "B"
  }

  implicit def ListToFoo[T: Foo]: Foo[List[T]] = toFoo { c =>
    c.map(toFoo(_)).
  }
}

class A
class B extends A

Теперь, если у меня есть, если я делаю toFoo(List(new A, new B), я получаю List("A", "A") вместо List("A", "B").Как я могу убедиться, что метод BtoFoo используется вместо AToFoo для классов с типом B?

1 Ответ

2 голосов
/ 20 марта 2012

неявное разрешение - это чисто механизм времени компиляции.Простой способ отличить подтипы здесь - это сопоставление внутри неявного.Удалите BToFoo в целом и вместо этого используйте версию A для обоих случаев

implicit val AIsFoo : Foo[A] = toFoo { 
  case b: B => "B"
  case a: A => "A"
}

Конечно, также возможно делегировать метод для части иерархии.Вы можете делегировать метод в A, overidde в B, и все еще иметь класс типов для List, где вы не можете добавить метод.

Вы также можете объявить Foo контравариантным.

...