特征用于在类之间共享接口和字段。它们类似于 Java 8 的接口。类和对象可以扩展特征,但特征不能被实例化,因此没有参数。
定义特征
最小特征只是关键字 trait
和一个标识符
trait HairColor
特征作为泛型类型和抽象方法时变得特别有用。
trait Iterator[A] {
def hasNext: Boolean
def next(): A
}
trait Iterator[A]:
def hasNext: Boolean
def next(): A
扩展 trait Iterator[A]
需要类型 A
和方法 hasNext
和 next
的实现。
使用特征
使用 extends
关键字来扩展特征。然后使用 override
关键字实现特征的任何抽象成员
trait Iterator[A] {
def hasNext: Boolean
def next(): A
}
class IntIterator(to: Int) extends Iterator[Int] {
private var current = 0
override def hasNext: Boolean = current < to
override def next(): Int = {
if (hasNext) {
val t = current
current += 1
t
} else 0
}
}
val iterator = new IntIterator(10)
iterator.next() // returns 0
iterator.next() // returns 1
trait Iterator[A]:
def hasNext: Boolean
def next(): A
class IntIterator(to: Int) extends Iterator[Int]:
private var current = 0
override def hasNext: Boolean = current < to
override def next(): Int =
if hasNext then
val t = current
current += 1
t
else
0
end IntIterator
val iterator = new IntIterator(10)
iterator.next() // returns 0
iterator.next() // returns 1
此 IntIterator
类将参数 to
作为上限。它 extends Iterator[Int]
,这意味着 next
方法必须返回 Int。
子类型化
在需要给定特征的情况下,可以使用特征的子类型。
import scala.collection.mutable.ArrayBuffer
trait Pet {
val name: String
}
class Cat(val name: String) extends Pet
class Dog(val name: String) extends Pet
val dog = new Dog("Harry")
val cat = new Cat("Sally")
val animals = ArrayBuffer.empty[Pet]
animals.append(dog)
animals.append(cat)
animals.foreach(pet => println(pet.name)) // Prints Harry Sally
import scala.collection.mutable.ArrayBuffer
trait Pet:
val name: String
class Cat(val name: String) extends Pet
class Dog(val name: String) extends Pet
val dog = Dog("Harry")
val cat = Cat("Sally")
val animals = ArrayBuffer.empty[Pet]
animals.append(dog)
animals.append(cat)
animals.foreach(pet => println(pet.name)) // Prints Harry Sally
特征 trait Pet
有一个抽象字段 name
,它在 Cat 和 Dog 的构造函数中得到实现。在最后一行,我们调用 pet.name
,它必须在特征 Pet
的任何子类型中实现。