Back-End

12 nov, 2012

Fazendo uma combinação de class e trait no Scala

100 visualizações
Publicidade

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/