Рассмотрим следующий надуманный пример реализации унарных и бинарных операций над выражениями вещественных чисел.
abstract class DoubleE
case class Negate(x: DoubleE) extends DoubleE
case class Reciprocal(x: DoubleE) extends DoubleE
case class Mult(lhs: DoubleE, rhs: DoubleE) extends DoubleE
case class Div(lhs: DoubleE, rhs: DoubleE) extends DoubleE
...
// a lot more binary operations
Теперь я хочу сделать что-то вроде:
(e: DoubleE) match {
case DoubleEUnary(x) => ... // use x ...
case DoubleEBinary(a, b) => ... // use a and b ...
}
а иногда мне даже хотелось бы сослаться на соответствующий тип; Например
e match {
case DoubeEBinary(a, b) => DoubleEBinary(b, a)
...
}
Некоторые из неудачных попыток, которые я пробовал:
abstract case class DoubleEBinary(a: DoubleE, b: DoubleE)
+ расширить от этого, но это не разрешено: Ошибка: ... наследование от случая к случаю запрещено. Чтобы обойти это ограничение, используйте экстракторы для сопоставления с образцом на неконечных узлахНамёк на ошибку выше:
abstract case class DoubleEBinary(a: DoubleE, b: DoubleE) def unapply(binOp: DoubleEBinary) = Some((a, b))
что тоже не работает: Ошибка: не найдено: значение DoubleEBinary
- Trying to use case aliases
case binOp @ (Mult(a, b) | Div(a, b) | ...) => ...
case binOp(a, b) @ (Mult(_, _) | Div(_, _) | ...) => ...
case (binOp @ Mult(a, b)) | (binOp @ Div(a, b)) => ...
Одна вещь, которую я не пробовал, - это перегрузка вложенными функциями, что кажется излишним...
Есть ли хороший способ сопоставить несколько классов случаев в сценариях, подобных приведенным выше?
Примечание. Добавление дополнительных методов, классов, трейтов в наследование — это нормально.