Scala дженерики с классом case, расширяющим запечатанный признак

#scala

#scala

Вопрос:

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

 class FruitProcessor[T <: Fruit] {
  def process(fruit: T) = {
    // Do something with fruit
  }
}

class FruitBlender[T <: Fruit] {
  val fruitProcessor = new FruitProcessor[T]

  def blend(fruit: T) = {
    fruit match {
      case b: Banana => fruitProcessor.process(b)
      case a: Apple => fruitProcessor.process(a)
    }
  }
}


sealed trait Fruit
case class Banana(id: String) extends Fruit
case class Apple(id: String) extends Fruit
  

Ошибка компиляции примерно такая: «найден банан, требуется T»

Что я здесь делаю не так?

Комментарии:

1. Удалите T и замените его Fruit .

Ответ №1:

process Метод требует аргумент типа T , но вы передаете ему значение типа Banana . Компилятор недостаточно умен, чтобы понять, что T это всегда Banana находится в пути кода, где fruitProcessor.process(b) вызывается. На самом деле вам вообще не нужно это выражение соответствия. В этом случае метод T in blend такой же, как и тот T , который process хочет. Так что вы можете просто позвонить fruitProcessor.process(fruit) .

Ответ №2:

Чтобы объяснить, что вы делаете: У вас есть FruitProcessor параметризованный подкласс T Fruit , который может process T s . Затем вы FoodBlender также создаете параметризованный подкласс T Fruit , который имеет a FoodProcessor[T] , то есть он может process иметь все виды T .

Поскольку вы можете использовать только process T and not [S <: Fruit] , то есть только конкретные экземпляры вашего подтипа Fruit T , с которыми параметризован blender , а не все Fruit s , это не может работать с конкретными типами Banana and Apples . T FruitBlender Например, на может быть class Pear extends Fruit , и в этом случае подпись blend будет def blend(fruit: Pear) , что, конечно, если не совместимо с Apple s или Banana s.