Шаблон класса типов в Scala не учитывает наследование? - PullRequest
9 голосов
/ 06 октября 2010

В некоторых случаях я разрабатываю API с использованием классов типов, однако я столкнулся с проблемой неявного разрешения.Как показано ниже, если существует неявный объект для типа A, но объект типа B extends A передается методу, то неявный объект не может быть найден.Есть ли способ заставить это работать, или вызывающие абоненты должны помещать неявные объекты в область действия для каждого подкласса?

Вот пример:

class A
class B extends A

class T[+X]

object T {
  implicit object TA extends T[A]
}

def call[X:T](x:X) = println(x)

// compiles
call(new A)
// doesn't compile
call(new B)

var a = new A
// compiles
call(a)

a = new B
// compiles
call(a)

val b = new B
// doesn't compile
call(b)

Это не скомпилируется со следующим выводом:

/private/tmp/tc.scala:16: error: could not find implicit value for evidence parameter of type this.T[this.B]
call(new B)
    ^
/private/tmp/tc.scala:28: error: could not find implicit value for evidence parameter of type this.T[this.B]
call(b)

Ответы [ 3 ]

7 голосов
/ 06 октября 2010

Вызов call(new B) означает call[B](new B)(tB) такой, что tb имеет тип T [B] или его подкласс.(Метод, который ожидает аргумент типа T, может ожидать только T или подкласс T, например, def foo(s: String) не может быть вызван с аргументом типа Any).T [A] не является подтипом T [B]

. Чтобы исправить, вы можете изменить T, чтобы определить T[-X].Это означает, что компилятор будет считать T [A] подтипом T [B]

4 голосов
/ 06 октября 2010

отлично работает следующее:

scala> def call[X](x: X)(implicit evidence: T[X]<:<T[X])  = println(x)
call: [X](x: X)(implicit evidence: <:<[T[X],T[X]])Unit

scala> call(new A)
line0$object$$iw$$iw$A@1d869b2

scala> call(new B)
line2$object$$iw$$iw$B@b3a5d1

scala> val b = new B
b: B = B@30e4a7

scala> call(b)
line2$object$$iw$$iw$B@30e4a7

В вашем случае компиляция не удалась, потому что def call[X:T](x:X) = println(x) рассматривается как call: [X](x: X)(implicit evidence$1: T[X])Unit. Чтобы передать подтип, вы можете использовать ограничения обобщенного типа.

2 голосов
/ 06 октября 2010

Попробуйте:

object T {
  implicit def TA[X <: A] = new T[X]
}

import T._

или просто:

implicit def TA[X <: A] = new T[X]
...