Truques em Scala – Extractors

0 comments

Posted on 5th novembro 2009 by gbenatti in Programação | Sem categoria | scala | truques

Scala muitas vezes me surpreende com a elegancia e integridade da linguagem. O que chamo aqui de integridade, é a forma como a linguagem combina vários conceitos de uma forma uniforme.

Uma das features interessantes de  Scala é que ela permite ao programador extrair informações de objetos usando pattern matching, por exemplo se você tiver o seguinte tipo chamado Email:

  1. case class Email(name: String, domain: String)

Seria possivel testar se um objeto é do tipo Email, e ao mesmo tempo retornar o name e domain com o seguinte código:

  1. unknownObject match {
  2.   case Email(name, domain) =>
  3.     println(name + " at " + domain)
  4.   case _ =>
  5.     println("It’s not an email")
  6. }

No caso de unknownObject ser declarado como:

  1. val unknownObject = Email("georges", "gbenatti.net")

A saida seria “georges at gbenatti.net”

Já se unknownObject fosse declarado como:

  1. val unknownObject: Any = "georges@gbeatti.net"

A saida seria “It’s not an email”

Mas não seria muito legal se fosse possivel fazer essa segunda opção funcionar ? Ai entra a elegância de Scala, você pode definir extractors que permitem que sejam extraidos dados de determinadas estruturas, sejam elas árvores, listas e até mesmo strings.

Um extractor é um objeto Scala que define um método unapply. A responsabilidade do unapply é fazer o matching de um valor e o separar em seus componentes, para o caso acima o extractor poderia ser definido assim:

  1. object EmailStr  {
  2.   def unapply(str: String): Option[(String, String)] = {
  3.     val parts = str split "@"
  4.     if (parts.length == 2) Some(parts(0), parts(1)) else None
  5.   }
  6. }

Definido esse extractor poderiamos reescrever o match da seguinte forma:

  1. unknownObject match {
  2.   case Email(name, domain) =>
  3.     println(name + " at " + domain)
  4.   case EmailStr(name, domain) =>
  5.     println(name + " at " + domain)
  6.   case _ =>
  7.     println("It’s not an email")
  8. }

E ele funcionaria tanto com objetos da classe Email quanto com strings no formato name@domain, ou seja, código final do usuário simples e elegante.

Até mais pp pessoal…

Nenhum comentário ainda.

Deixe um comentário