В частности, это минимальный пример:Почему Scala не отслеживает анонимные типы?
trait A[T1, T2] {
def convert(t1: T1): T2
def reverse(t2: T2): T1
}
class B extends A[Int, Double] {
def convert(i: Int): Double = i.toDouble
def reverse(i: Double): Int = i.toInt
}
class C extends A[Int, Float] {
def convert(i: Int): Float = i.toFloat
def reverse(i: Float): Int = i.toInt
}
val bOrC: A[Int, _] = if (System.nanoTime % 2 == 0) {
new B
} else {
new C
}
bOrC.convert(7)
bOrC.reverse(bOrC.convert(7))
потерпит неудачу на последней строке:
scala> bOrC.reverse(bOrC.convert(7))
<console>:12: error: type mismatch;
found : (some other)_$1(in value bOrC)
required: _$1(in value bOrC)
bOrC.reverse(bOrC.convert(7))
кажется, что тип _$1
одинакова в обоих возвращаемый тип и аргумент - это bOrC
T2
тип, каким бы он ни был. Локальный тип вывода не должен быть проблемой здесь. Почему я не могу это сделать?
Есть ли обходной путь, который не такой уродливый, как следующее?
trait A[T1, T2] {
def convert(t1: T1): T2
def reverse(t2: X): T1
type X = T2
}
// ... rest as before
bOrC.reverse(bOrC.convert(7).asInstanceOf[bOrC.X])
Edit: выглядит, как если бы вы сказать Scala это тот же самый тип, все обрабатывается. Это избавляется от глупой type X
:
def thereAndBack[T2](a: A[Int, T2], b: Int) = a.reverse(a.convert(b))
thereAndBack(bOrC)
Подчеркивание в этом контексте не является «анонимным типом», что это _existential типа _-- означает, что вы хотите сказать, компилятор вы _don't care_, что типа есть, поэтому компилятор будет счастливо лечить это как таковое. –
Там есть диссонанс между вашим требованием запоминания типа и использования экзистенциального типа, который делает точно противоположное тому, что вы хотите. –
@ m-z ОК, да, мне все равно, какой это тип. Но это тот же тип, который возвращается и используется, что бы это ни было. Там что-то не хватает. – VF1