Учебники

Скала – Черты

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

Черты используются для определения типов объектов путем указания сигнатуры поддерживаемых методов. Scala также позволяет частично реализовывать черты, но черты могут не иметь параметров конструктора.

Определение черты выглядит точно так же, как определение класса, за исключением того, что оно использует черту ключевого слова. Ниже приведен базовый пример синтаксиса черты.

Синтаксис

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

Эта черта состоит из двух методов isEqual и isNotEqual . Здесь мы не дали никакой реализации для isEqual, где другой метод имеет свою реализацию. Дочерние классы, расширяющие черту, могут дать реализацию для не реализованных методов. Таким образом, черта очень похожа на то, что у нас есть абстрактные классы в Java.

Предположим, что пример признака Equal содержит два метода isEqual () и isNotEqual () . Признак Equal содержит один реализованный метод isEqual (), поэтому, когда пользовательский класс Point расширяет признак Equal , должна быть обеспечена реализация метода isEqual () в классе Point .

Здесь необходимо знать два важных метода Scala, которые используются в следующем примере.

  • obj.isInstanceOf [Point] Для проверки Тип obj и Point одинаковы не являются.

  • obj.asInstanceOf [Point] означает точное приведение типа объекта obj и возвращает тот же объект, что и тип Point.

obj.isInstanceOf [Point] Для проверки Тип obj и Point одинаковы не являются.

obj.asInstanceOf [Point] означает точное приведение типа объекта obj и возвращает тот же объект, что и тип Point.

Попробуйте следующий пример программы для реализации черт.

пример

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))
   }
}

Сохраните вышеуказанную программу в Demo.scala . Следующие команды используются для компиляции и выполнения этой программы.

команда

\>scalac Demo.scala
\>scala Demo

Выход

true
false
true

Классы ценности и универсальные черты

Классы значений – это новый механизм в Scala, позволяющий избежать выделения объектов времени выполнения. Он содержит основной конструктор с ровно одним параметром val . Он содержит только методы (def), недопустимые var, val, вложенные классы, признаки или объекты. Значение класса не может быть расширен другим классом. Это может быть возможно путем расширения вашего класса значений с AnyVal. Безопасность типов пользовательских типов данных без затрат времени выполнения.

Давайте рассмотрим примеры классов значений «Вес», «Рост», «Электронная почта», «Возраст» и т. Д. Для всех этих примеров не требуется выделять память в приложении.

Класс значения не может расширять черты. Чтобы позволить классам значений расширять черты, вводятся универсальные черты , которые распространяются на Any .

пример

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
   }
}

Сохраните вышеуказанную программу в Demo.scala . Следующие команды используются для компиляции и выполнения этой программы.

команда

\>scalac Demo.scala
\>scala Demo

Выход

Это даст вам хэш-код класса Wrapper.

Wrapper@13

Когда использовать черты?

Не существует твердого правила, но вот несколько рекомендаций для рассмотрения –

Если поведение не будет использоваться повторно, сделайте его конкретным классом. Это не многоразовое поведение в конце концов.

Если это может быть повторно использовано в нескольких, не связанных между собой классах, сделайте это признаком. Только черты могут быть смешаны в разных частях иерархии классов.

Если вы хотите наследовать от него в коде Java, используйте абстрактный класс.

Если вы планируете распространять его в скомпилированной форме и ожидаете, что внешние группы будут писать классы, унаследованные от него, вы можете склоняться к использованию абстрактного класса.

Если эффективность очень важна, склоняйтесь к использованию класса.