当前位置: 首页 > 文档资料 > Scala 中文文档 >

Traits

优质
小牛编辑
127浏览
2023-12-01

特征封装了方法和字段定义,然后可以通过将它们混合到类中来重用它们。 与类继承不同,其中每个类必须仅从一个超类继承,类可以混合任意数量的特征。

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

特征定义看起来就像一个类定义,除了它使用关键字trait 。 以下是特质的基本示例语法。

语法 (Syntax)

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

该特征由两个方法isEqualisNotEqual 。 在这里,我们没有给出isEqual的任何实现,而另一种方法有其实现。 扩展特征的子类可以为未实现的方法提供实现。 所以特征与Java中的abstract classes非常相似。

让我们假设一个特征的例子Equal包含两个方法isEqual()isNotEqual() 。 特性Equal包含一个isEqual()实现方法,因此当用户定义的类Point扩展特性Equal ,应该提供Point类中的isEqual()方法的实现。

这里需要知道Scala的两个重要方法,它们在下面的例子中使用。

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

  • obj.asInstanceOf [Point]表示通过获取对象obj类型并返回与Point类型相同的obj来精确转换。

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

例子 (Example)

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 。 以下命令用于编译和执行此程序。

Command

\>scalac Demo.scala
\>scala Demo

输出 (Output)

true
false
true

价值类和通用特征

值类是Scala中的新机制,以避免分配运行时对象。 它包含一个只有一个val参数的主构造函数。 它仅包含方法(def),不允许使用var,val,嵌套类,特征或对象。 值类不能由另一个类扩展。 这可以通过使用AnyVal扩展您的值类来实现。 自定义数据类型的类型安全性,没有运行时开销。

让我们举一个值类,权重,高度,电子邮件,年龄等的示例。对于所有这些示例,不需要在应用程序中分配内存。

值类不允许扩展特征。 为了允许值类扩展特征,引入了针对Any扩展的universal traits

例子 (Example)

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 。 以下命令用于编译和执行此程序。

Command

\>scalac Demo.scala
\>scala Demo

输出 (Output)

它将为您提供Wrapper类的哈希码。

Wrapper@13

何时使用特征?

没有确定的规则,但这里有一些指导方针需要考虑 -

  • 如果不再重用该行为,那么将其作为具体类。 毕竟,这不是可重用的行为。

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

  • 如果要在Java代码中inherit它,请使用抽象类。

  • 如果您计划以编译形式分发它,并且您希望外部组编写从其继承的类,您可能倾向于使用抽象类。

  • 如果效率非常重要,那就倾向于使用一门课程。