Scala实践12
1、内部类和抽象类型成员作为对象成员
? ? ? ? 在Scala中,可以让类将其他类作为成员。这些内部类是封闭类的成员。在Scala中,这样的内部类绑定到外部对象。假设希望编译器在编译时阻止我们混合哪些节点属于哪个图。路径相关类型提供了解决方案。 为了说明差异,绘制了图数据类型的实现: class Graph { class Node { var connectedNodes: List[Node] = Nil def connectTo(node: Node) { if (connectedNodes.find(node.equals).isEmpty) { connectedNodes = node :: connectedNodes } } } var nodes: List[Node] = Nil def newNode: Node = { val res = new Node nodes = res :: nodes res } } 上例将图表表示为节点列表( val graph1: Graph = new Graph val node1: graph1.Node = graph1.newNode val node2: graph1.Node = graph1.newNode val node3: graph1.Node = graph1.newNode node1.connectTo(node2) node3.connectTo(node1) ? ? ? ? 明确宣布的类型 如果现在有两个图形,Scala的类型系统不允许我们将一个图形中定义的节点与另一个图形的节点混合,因为另一个图形的节点具有不同的类型。这是一个非法的程序: val graph1: Graph = new Graph val node1: graph1.Node = graph1.newNode val node2: graph1.Node = graph1.newNode node1.connectTo(node2) // 合法的 val graph2: Graph = new Graph val node3: graph2.Node = graph2.newNode node1.connectTo(node3) // 非法的 class Graph { class Node { var connectedNodes: List[Graph#Node] = Nil def connectTo(node: Graph#Node) { //Graph#Node与上面匹配 if (connectedNodes.find(node.equals).isEmpty) { connectedNodes = node :: connectedNodes } } } var nodes: List[Node] = Nil def newNode: Node = { val res = new Node nodes = res :: nodes res } }
? ? ? ? ?抽象类型(如traits和抽象类)又可以具有抽象类型成员。这意味着具体实现定义了实际类型。这是一个例子: trait Buffer { type T val element: T } 这里定义了一个摘要 abstract class SeqBuffer extends Buffer { type U type T <: Seq[U] def length = element.length } 注意如何 具有抽象类型成员的特征或类通常与匿名类实例一起使用。为了说明这一点,我们现在看一个程序,它处理一个引用整数列表的序列缓冲区: 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)
2、复合类型? ? ? 有时需要表达对象的类型是其他几种类型的子类型。在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 = { //... } 复合类型可以由多个对象类型组成,它们可以具有单个细化,可以用于缩小现有对象成员的签名。一般形式是: ? 3、自我类型自我类型是一种声明特征必须混合到另一个特征中的方法,即使它没有直接扩展它。这使得依赖的成员可以在没有导入的情况下使用。 自我类型是一种缩小 要在特征中使用自我类型,请写入标识符,要混合的另一个特征的类型,以及 trait User { def username: String } trait Tweeter { this: User => def tweet(tweetText: String) = println(s"$username: $tweetText") } class VerifiedTweeter(val username_ : String) extends Tweeter with User { def username = s"real $username_" } val realBeyoncé = new VerifiedTweeter("Beyoncé") realBeyoncé.tweet("Just spilled my glass of lemonade") 因为 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |