Scala - Traços

Uma característica encapsula definições de método e campo, que podem ser reutilizadas misturando-as em classes. Ao contrário da herança de classe, na qual cada classe deve herdar de apenas uma superclasse, uma classe pode misturar qualquer número de características.

Traits são usados ​​para definir tipos de objetos especificando a assinatura dos métodos suportados. Scala também permite que as características sejam parcialmente implementadas, mas as características podem não ter parâmetros de construtor.

Uma definição de característica se parece com uma definição de classe, exceto que usa a palavra-chave trait. A seguir está o exemplo básico de sintaxe de trait.

Sintaxe

trait Equal {
   def isEqual(x: Any): Boolean
   def isNotEqual(x: Any): Boolean = !isEqual(x)
}

Esta característica consiste em dois métodos isEqual e isNotEqual. Aqui, não fornecemos nenhuma implementação para isEqual onde outro método tem sua implementação. As classes filhas que estendem uma característica podem fornecer implementação para os métodos não implementados. Portanto, um traço é muito semelhante ao que temosabstract classes em Java.

Vamos supor um exemplo de traço Equal contém dois métodos isEqual() e isNotEqual(). O traçoEqual contém um método implementado que é isEqual() então, quando a classe definida pelo usuário Point estende o traço Equal, implementação para isEqual() método em Point classe deve ser fornecida.

Aqui é necessário conhecer dois métodos importantes de Scala, que são usados ​​no exemplo a seguir.

  • obj.isInstanceOf [Point] Para verificar o tipo de obj e o ponto são iguais, não.

  • obj.asInstanceOf [Point] significa moldagem exata, pegando o tipo de objeto de objeto e retorna o mesmo tipo de objeto de ponto.

Experimente o programa de exemplo a seguir para implementar características.

Exemplo

trait Equal {
   def isEqual(x: Any): Boolean
   def isNotEqual(x: Any): Boolean = !isEqual(x)
}

class Point(xc: Int, yc: Int) extends Equal {
   var x: Int = xc
   var y: Int = yc
   
   def isEqual(obj: Any) = obj.isInstanceOf[Point] && obj.asInstanceOf[Point].x == y
}

object Demo {
   def main(args: Array[String]) {
      val p1 = new Point(2, 3)
      val p2 = new Point(2, 4)
      val p3 = new Point(3, 3)

      println(p1.isNotEqual(p2))
      println(p1.isNotEqual(p3))
      println(p1.isNotEqual(2))
   }
}

Salve o programa acima em Demo.scala. Os seguintes comandos são usados ​​para compilar e executar este programa.

Comando

\>scalac Demo.scala
\>scala Demo

Resultado

true
false
true

Classes de valor e traços universais

As classes de valor são um novo mecanismo no Scala para evitar a alocação de objetos de tempo de execução. Ele contém um construtor primário com exatamente umvalparâmetro. Ele contém apenas métodos (def) não permitidos, var, val, classes aninhadas, características ou objetos. A classe de valor não pode ser estendida por outra classe. Isso pode ser possível estendendo sua classe de valor com AnyVal. A segurança de tipos de tipos de dados personalizados sem a sobrecarga do tempo de execução.

Vamos dar exemplos de classes de valor Peso, Altura, Email, Idade, etc. Para todos esses exemplos, não é necessário alocar memória no aplicativo.

Uma classe de valor não tem permissão para estender características. Para permitir que as classes de valor estendam as características,universal traits são introduzidos que se estendem por Any.

Exemplo

trait Printable extends Any {
   def print(): Unit = println(this)
}
class Wrapper(val underlying: Int) extends AnyVal with Printable

object Demo {
   def main(args: Array[String]) {
      val w = new Wrapper(3)
      w.print() // actually requires instantiating a Wrapper instance
   }
}

Salve o programa acima em Demo.scala. Os seguintes comandos são usados ​​para compilar e executar este programa.

Comando

\>scalac Demo.scala
\>scala Demo

Resultado

Ele fornecerá o código hash da classe Wrapper.

Wrapper@13

Quando usar características?

Não existe uma regra firme, mas aqui estão algumas diretrizes a serem consideradas -

  • Se o comportamento não for reutilizado, torne-o uma classe concreta. Afinal, não é um comportamento reutilizável.

  • Se puder ser reutilizado em várias classes não relacionadas, torne-o uma característica. Apenas características podem ser misturadas em diferentes partes da hierarquia de classes.

  • Se você quiser inherit a partir dele no código Java, use uma classe abstrata.

  • Se você planeja distribuí-lo em forma compilada e espera que grupos externos escrevam classes herdadas dele, você pode se inclinar a usar uma classe abstrata.

  • Se a eficiência é muito importante, tente usar uma classe.