Enquanto eu desenvolvia com Scala, descobri que é possível fazer combinações de uma classe com traits. Pode parecer óbvio, se você já sabe, mas eu particularmente não sabia.
O que aconteceu é que eu precisava de algo como combinar esse tipo de combinação… E este artigo fala sobre algo de Scala que eu amo: ele se torna intuitivo depois de um tempo. Então, como foi que descobri que tal correspondência é possível? Eu simplesmente tentei … =)
O recurso se parece com isto:
msg match { case x: X with Z => println("matching combination!") }
Nesse caso, X seria uma classe e Z, uma trait. O case x será acionado apenas se msg for uma instância da class X e se misturar com a trait Z. Com isso, certifique-se de ter acesso a todos os membros, tanto da classe quanto das traits, enquanto estiver muito seguro sobre o tipo de correspondência. Nenhuma combinação não suportada irá passar, e não há necessidade de castings, como seria necessário em Java.
Vamos tentar um exemplo fictício. Imagine que temos uma classe Superman, e duas traits: BlueCape e RedCape, como o seguinte código:
class Superman(val realname: String) trait BlueCape trait RedCape
Agora, queremos corresponder em uma instância de Superman, mas queremos saber se é falsa ou não. Finalmente, também queremos imprimir o nome do cara, o que significa que precisamos de acesso ao campo realname. Você pode fazer isso assim:
def whichSuperman(superman: AnyRef) = superman match { case s: Superman with RedCape => println("real superman: " + s.realname) case f: Superman with BlueCape => println("fake superman: " + f.realname) }
Flexível e do tipo seguro! E se traits tivessem qualquer campo, também seríamos capazes de acessá-los. Pequeno exemplo de código:
val mys = new Superman("clark") with RedCape val myf = new Superman("clurk") with BlueCape whichSuperman(mys) whichSuperman(myf)
A parte que corresponde à classe não é muito útil nesse exemplo, uma vez que isso poderia ser definido no parâmetro de função, mas estava em meu cenário local, onde estamos usando atores e as mensagens podem ser AnyRef.
Se quiser saber um pouco mais sobre a correspondência de padrões, eu escrevi sobre isso há um tempo aqui. Eu também descrevi como combinar uma série de números aqui.
***
Texto original disponível em http://jcranky.com/2011/12/19/matching-a-combination-of-class-and-trait-in-scala/