【Scala之旅】特质与高级类型
特质特质用于在类之间共享接口和字段。它们类似于Java 8的接口。类和对象可以扩展特征,但是特质不能被实例化,因此没有参数。 定义特质一个最小的特质就是关键字 trait HairColor 作为泛型类型和抽象方法,特质显得特别有用。 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() // prints 0 iterator.next() // prints 1 这个 子类型可以在需要特征的地方使用子类型。 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
抽象类型特质和抽象类可以有一个抽象类型的成员。这意味着具体的实现定义了实际的类型。这里有一个例子: trait Buffer { type T val element: T } 这里我们定义了一个抽象类型 abstract class SeqBuffer extends Buffer { type U type T <: Seq[U] def length = element.length } 请注意我们是如何使用另一个抽象类型 带有抽象类型成员的特质或类经常与匿名类实例化相结合使用。为了说明这一点,我们现在来看一个程序,它处理一个 SeqBuffer,引用了一个 Int 列表: abstract class IntSeqBuffer extends SeqBuffer { type U = Int } def newIntSeqBuf(elem1: Int,elem2: Int): IntSeqBuffer = new IntSeqBuffer { type T = List[U] val element = List(elem1,elem2) } val buf = newIntSeqBuf(7,8) println("length = " + buf.length) println("content = " + buf.element) 这里有一个使用匿名类 也可以将抽象类型成员转换为类的类型参数,反之亦然。下面是上述代码的一个版本,它只使用类型参数: abstract class Buffer[+T] { val element: T } abstract class SeqBuffer[U,+T <: Seq[U]] extends Buffer[T] { def length = element.length } def newIntSeqBuf(e1: Int,e2: Int): SeqBuffer[Int,Seq[Int]] = new SeqBuffer[Int,List[Int]] { val element = List(e1,e2) } val buf = newIntSeqBuf(7,8) println("length = " + buf.length) println("content = " + buf.element) 注意,我们必须在这里使用型变注解( 自身类型自身类型是一种声明一种特质必须被混入到另一种特质的方式,尽管它并没有直接地扩展它。这使得依赖项的成员可以不用导入。 自身类型是小写 要在一个特质中使用自我类型,编写一个标识符,将另一个特质混入在一起,以及一个 trait User { def username: String } trait Tweeter { this: User => // reassign this def tweet(tweetText: String) = println(s"$username: $tweetText") } class VerifiedTweeter(val username_ : String) extends Tweeter with User { // We mixin User because Tweeter required it def username = s"real $username_" } val realBeyoncé = new VerifiedTweeter("Beyoncé") realBeyoncé.tweet("Just spilled my glass of lemonade") // prints "real Beyoncé: Just spilled my glass of lemonade" 因为我们说 复合类型有时,有必要表示对象的类型是其他类型的子类型。在Scala中,这可以通过复合类型 的帮助来表示,这些类型是对象类型的交集。 假设我们有两个特质 trait Cloneable extends java.lang.Cloneable { override def clone(): Cloneable = { super.clone().asInstanceOf[Cloneable] } } trait Resetable { def reset: Unit } 现在假设我们要写一个函数 def cloneAndReset(obj: ?): Cloneable = { val cloned = obj.clone() obj.reset cloned } 问题是,参数 这是更新的函数: def cloneAndReset(obj: Cloneable with Resetable): Cloneable = { //... } 复合类型可以由几个对象类型组成,它们可能有一个单独的细化,可以用来缩小现有对象成员的签名。一般的形式是: 在抽象类型中给出了细化的例子。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |