Почему перенос метода в другой метод останавливает несовпадение типов в Scala - использование подчеркивания в параметре типа в сопоставлении с образцом? - PullRequest
0 голосов
/ 03 января 2019

В следующем блоке кода (и с scala 2.11, и с 2.12) метод apply не компилируется, а applyInlined -.

package blar

trait Bar[T]

class A
class B
class C

trait Exploder[T] {
  // Removing explode and changing Foo so that
  // flatMap takes no param means it will compile
  def explode(product: C): Seq[T]
  val bar: Bar[T]
}

case object Exploder1 extends Exploder[A] {
  def explode(product: C): Seq[A] = ???
  val bar: Bar[A] = ???
}

case object Exploder2 extends Exploder[B] {
  def explode(product: C): Seq[B] = ???
  val bar: Bar[B] = ???
}

object Thing {
  def apply(): Unit = List(Exploder1, Exploder2).foreach {
    case exploder: Exploder[_] =>
      wrapped(exploder)
  }

  def applyInlined(): Unit = List(Exploder1, Exploder2).foreach {
    case exploder: Exploder[_] =>
      flatMap(exploder.explode)(exploder.bar)
  }

  def flatMap[U: Bar](explode: C => TraversableOnce[U]): Unit = ???

  def wrapped[T](exploder: Exploder[T]): Unit =
    flatMap(exploder.explode)(exploder.bar)
}

Сообщение об ошибке

[error] .../src/main/scala/blar/Bar.scala:34:42: type mismatch;
[error]  found   : blar.Bar[_1]
[error]  required: blar.Bar[Object]
[error] Note: _1 <: Object, but trait Bar is invariant in type T.
[error] You may wish to define T as +T instead. (SLS 4.5)
[error]       flatMap(exploder.explode)(exploder.bar)
[error]                                          ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed
[error] Total time: 4 s, completed 03-Jan-2019 13:43:45
  1. Мой главный вопрос: почему?Это ошибка?

Как видите, applyInlined отличается только тем, что содержит тело метода wrapped.Это означает, что каким-то образом дополнительная упаковка некоторого кода в методе «обманула» компилятор в работу.

Другой вопрос: можете ли вы вспомнить дизайн / хак, который бы избегал такого рода вещей без , делающего Blar ковариантным?Как я могу заставить встроенную версию скомпилировать?Могу ли я сделать это с asInstanceOf

Что такое scala, выводящая тип, для вызова wrapped без явного параметра типа?

1 Ответ

0 голосов
/ 03 января 2019
  1. Я не знаю.Экспериментальные данные показывают, что это как-то связано с наличием / отсутствием явной аннотации типа [Exploder[_]] на List.Без List[Exploder[_]] выводимый тип списка становится

    List[Product with Serializable with Exploder[_ >: B with A <: Object]]
    

    и по какой-либо причине он каким-то образом портит последующее сопоставление с образцом.Нижняя граница B with A выглядит немного подозрительной для меня, но я не могу объяснить, почему она мешает сопоставлению с образцом.

  2. Нет, к счастью, нет asInstanecOf sтребуется.Оба следующих варианта работают нормально:

    def applyInlined: Unit = List[Exploder[_]](Exploder1, Exploder2).foreach {
      case exploder: Exploder[t] => {
        flatMap(exploder.explode)(exploder.bar)
      }
    }
    

    то же самое с отдельно объявленной неявной переменной (обратите внимание, что теперь у вас есть некоторый тип t для ссылки):

    def applyInlined2: Unit = List[Exploder[_]](Exploder1, Exploder2).foreach {
      case exploder: Exploder[t] => {
        implicit val bar: Bar[t] = exploder.bar
        flatMap(exploder.explode)
      }
    }
    

    См. Вывод параметра типа в шаблонах для получения более подробной информации о [t] -части.

  3. Я предполагаю, что это синтетический фиктивный тип _1.

...