Сопоставление шаблонов печати утки Scala

У меня есть класс case, подобный следующему:

// parent class
sealed abstract class Exp()

// the case classes I want to match have compatible constructors
case class A (a : Exp, b : Exp) extends Exp
case class B (a : Exp, b : Exp) extends Exp
case class C (a : Exp, b : Exp) extends Exp

// there are other case classes extending Exp that have incompatible constructor, e.g.
//     case class D (a : Exp) extends Exp
//     case class E () extends Exp
// I don't want to match them

Я хочу соответствовать:

var n : Exp = ...
n match {
    ...
    case e @ A (a, b) => 
        foo(e, a)
        foo(e, b)
    case e @ B (a, b) => 
        foo(e, a)
        foo(e, b)
    case e @ C (a, b) => 
        foo(e, a)
        foo(e, b)
    ...
}

def foo(e : Exp, abc : Exp) { ... }

есть ли способ объединить эти три случая в один случай (без добавления промежуточного родительского класса к A, B, C)? Я не могу изменить определение A, B, C или Exp. Что-то подобное:

var n : Exp = ...
n match {
    ...
    case e @ (A | B | C) (a, b) => // invalid syntax
        foo(e, a)
        foo(e, b)
    ...
}

что явно не работает, и не работает:

var n : Exp = ...
n match {
    ...
    case e @ (A (a, b) | B (a, b) | C (a, b)) => // type error
        foo(e, a)
        foo(e, b)
    ...
}

person Lie Ryan    schedule 03.10.2012    source источник


Ответы (1)


Хотя следующее «решение» на самом деле представляет собой просто другой способ написания того, что у вас уже есть, оно может помочь, если вам нужно использовать один и тот же match более чем в одном месте и вы хотите избежать дублирования кода.

Отменяется следующий пользовательский параметр:

object ExpABC {
    def unapply(e:Exp):Option[(Int, Int)] = e match {
        case A(a, b) => Some(a, b)
        case B(a, b) => Some(a, b)
        case C(a, b) => Some(a, b)
        case _ => None
    }
}

позволяет вам писать

n match {
    case e @ ExpABC(a, b) =>
        println(e)
        println(a)
        println(b)
}

Таким образом, вам вообще не нужно изменять исходные классы. Я не знаю лучшего способа сделать это, который не включает изменение классов A/B/C, но я очень хочу научиться @ Stackoverflow;)

person fresskoma    schedule 03.10.2012