Scala: Typecast без явно известного параметра типа

Рассмотрим следующий пример:

case class C[T](x:T) {
  def f(t:T) = println(t)
  type ValueType = T
}

val list = List(1 -> C(2), "hello" -> C("goodbye"))

for ((a,b) <- list) {
  b.f(a)
}

В этом примере я знаю (гарантия времени выполнения), что типa будет какой-тоT, а такжеb будет иметь типC[T] с тем жеT, Конечно, компилятор не может этого знать, поэтому мы получаем ошибку при набореb.f(a).

Чтобы сказать компилятору, что этот вызов в порядке, нам нужно выполнить typecast à lab.f(a.asInstanceOf[T]), К несчастью,T здесь не известно Итак, мой вопрос: как мне переписатьb.f(a) чтобы этот код компилировался?

Я ищу решение, которое не включает в себя сложные конструкции (чтобы код был читабелен) и было бы «чистым» в том смысле, что мы не должны полагаться на стирание кода, чтобы оно работало (см. Первый подход ниже).

У меня есть несколько подходов к работе, но я нахожу их неудовлетворительными по разным причинам.

Подходы, которые я пробовал:
b.asInstanceOf[C[Any]].f(a)

Это работает и достаточно читабельно, но основано на «лжи».b не типC[Any]и единственная причина, по которой мы не получаем ошибку времени выполнения, заключается в том, что мы полагаемся на ограничения JVM (стирание типов). Я думаю, что это хороший стиль только для использованияx.asInstanceOf[X] когда мы знаем, чтоx действительно типаX.

  b.f(a.asInstanceOf[b.ValueType])

Это должно работать в соответствии с моим пониманием системы типов. Я добавил участникаValueType к классуC для того, чтобы иметь возможность явно ссылаться на параметр типаT, Однако при таком подходе мы получаем загадочное сообщение об ошибке:

Error:(9, 22) type mismatch;
 found   : b.ValueType
    (which expands to)  _1
 required: _1
  b.f(a.asInstanceOf[b.ValueType])
                    ^

Зачем? Кажется, жаловаться, что мы ожидаем типа_1 но получил тип_1! (Но даже если этот подход работает, он ограничен случаями, когда у нас есть возможность добавить членаValueType вC, ЕслиC это некоторый существующий класс библиотеки, мы тоже не можем этого сделать.)

for ((a,b) <- list.asInstanceOf[List[(T,C[T]) forSome {type T}]]) {
  b.f(a)
}

Это работает и семантически правильно (то есть, мы не "лжем" при вызовеasInstanceOf). Ограничение в том, что это несколько нечитаемо. Кроме того, это несколько специфично для нынешней ситуации: еслиa,b не приходят из того же итератора, то где мы можем применить этот тип приведения? (Этот код также имеет побочный эффект, который слишком сложен для Intelli / J IDEA 2016.2, что выделяет его как ошибку в редакторе.)

  val (a2,b2) = (a,b).asInstanceOf[(T,C[T]) forSome {type T}]
  b2.f(a2)

Я бы ожидал, что это сработает сa2,b2 теперь должны быть типыT а такжеC[T] для того же экзистенциальногоT, Но мы получаем ошибку компиляции:

Error:(10, 9) type mismatch;
 found   : a2.type (with underlying type Any)
 required: T
  b2.f(a2)
       ^

Зачем? (Кроме того, у этого подхода есть недостаток в том, что он несет затраты времени выполнения (я думаю) из-за создания и уничтожения пары.)

  b match {
    case b : C[t] => b.f(a.asInstanceOf[t])
  }

Это работает. Но заключение кода в соответствие делает код гораздо менее читабельным. (И это также слишком сложно для Intelli / J.)

Ответы на вопрос(4)

Ваш ответ на вопрос