Scala 特征(Traits)

Scala 特征(Traits)

特征(Traits)封装了方法和字段定义,可以通过将其混入类中来重用。与类继承不同,在类继承中,每个类只能继承一个超类,而类可以混入任意数量的特征。

特征用于通过指定支持的方法的签名来定义对象类型。Scala还允许对特征进行部分实现,但是特征不能有构造函数参数。

特征定义看起来和类定义一样,只是使用关键字 trait 。以下是特征的基本示例语法。

语法

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

这个特质由两个方法组成 isEqualisNotEqual 。在这里,我们没有给isEqual方法提供任何实现,而另一个方法则有它的实现。继承特质的子类可以为未实现的方法提供实现。因此,特质与Java中的抽象类非常相似。

让我们假设一个特质 Equal 的示例,其中包含两个方法 isEqual()isNotEqual() 。特质 Equal 包含一个已实现的方法 isEqual() ,因此当用户定义的类 Point 扩展特质 Equal 时,需要提供 Point 类中 isEqual() 方法的实现。

在这里,有两个Scala中使用的重要方法需要了解,它们在以下示例中使用。

  • obj.isInstanceOf [Point] 检查obj和Point的类型是否相同。

  • obj.asInstanceOf [Point] 表示通过将对象obj的类型转换为Point类型来进行准确的类型转换,并返回相同的obj。

尝试以下示例程序来实现特质。

示例

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,可以实现自定义数据类型的类型安全性,而不会增加运行时开销。

让我们以值类Weight、Height、Email、Age等为例。对于所有这些示例,在应用程序中不需要分配内存。

值类不允许扩展特质。为了允许值类扩展特质,引入了扩展任何类型的 通用特质

示例

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

什么时候使用Traits?

并没有明确的规定,但以下是一些考虑因素:

  • 如果行为不会被重用,那么将其作为一个具体类。毕竟它不是可重用的行为。

  • 如果可能在多个无关的类中重用它,那么将其作为一个trait。只有trait可以混合到类层次结构的不同部分中。

  • 如果你想在Java代码中从中继承,使用一个抽象类。

  • 如果你计划以编译形式分发它,并且你期望外部组织编写从中继承的类,那么你可能倾向于使用一个抽象类。

  • 如果效率非常重要,倾向于使用一个类。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程