Scala 什么更新PrefixMap的继承映射?
运行《Scala编程》(第3版)一书中的PrefixMap示例,以及Scala集合的体系结构一章中的PrefixMap示例,我不明白调用update时是什么更新了PrefixMap的继承映射。 代码如下:Scala 什么更新PrefixMap的继承映射?,scala,scala-collections,Scala,Scala Collections,运行《Scala编程》(第3版)一书中的PrefixMap示例,以及Scala集合的体系结构一章中的PrefixMap示例,我不明白调用update时是什么更新了PrefixMap的继承映射。 代码如下: import collection._ class PrefixMap[T] extends mutable.Map[String, T] with mutable.MapLike[String, T, PrefixMap[T]] { val id: Long = Pref
import collection._
class PrefixMap[T]
extends mutable.Map[String, T]
with mutable.MapLike[String, T, PrefixMap[T]] {
val id: Long = PrefixMap.nextId
var suffixes: immutable.Map[Char, PrefixMap[T]] = Map.empty
var value: Option[T] = None
def get(s: String): Option[T] =
if (s.isEmpty) value
else suffixes get s(0) flatMap (_.get(s substring 1))
def withPrefix(s: String): PrefixMap[T] =
if (s.isEmpty) this
else {
val leading = s(0)
suffixes get leading match {
case None =>
suffixes = suffixes + (leading -> empty)
case _ =>
}
val ret = suffixes(leading) withPrefix (s substring 1)
println("withPrefix: ends with: id="+this.id+", size="+this.size+", this="+this)
ret
}
override def update(s: String, elem: T) = {
println("update: this before withPrefix: id="+this.id+", size="+this.size+", return="+this)
val pm = withPrefix(s)
println("update: withPrefix returned to update: id="+pm.id+", size="+pm.size+", return="+pm)
println("===> update: this after withPrefix and before assignment to pm.value : id="+this.id+", size="+this.size+", return="+this)
pm.value = Some(elem)
println("===> update: this after assinment to pm.value: id="+this.id+", size="+this.size+", return="+this)
}
override def remove(s: String): Option[T] =
if (s.isEmpty) { val prev = value; value = None; prev }
else suffixes get s(0) flatMap (_.remove(s substring 1))
def iterator: Iterator[(String, T)] =
(for (v <- value.iterator) yield ("", v)) ++
(for ((chr, m) <- suffixes.iterator;
(s, v) <- m.iterator) yield (chr +: s, v))
def += (kv: (String, T)): this.type = { update(kv._1, kv._2); this }
def -= (s: String): this.type = { remove(s); this }
override def empty = new PrefixMap[T]
}
object PrefixMap {
var ids: Long = 0
def nextId: Long = { PrefixMap.ids+=1; ids }
}
object MyApp extends App {
val pm = new PrefixMap[Int]
pm.update("a", 0)
println(pm)
}
导入集合_
类前缀映射[T]
扩展mutable.Map[String,T]
使用mutable.MapLike[String,T,PrefixMap[T]]{
valid:Long=PrefixMap.nextId
变量后缀:immutable.Map[Char,PrefixMap[T]]=Map.empty
var值:选项[T]=无
def get(s:字符串):选项[T]=
如果(s.isEmpty)值
else后缀get s(0)flatMap(u.get(s子字符串1))
def with prefix(s:String):PrefixMap[T]=
如果我没有这个
否则{
val前导=s(0)
后缀获得领先匹配{
案例无=>
后缀=后缀+(前导->空)
案例=>
}
val ret=带前缀(s子字符串1)的后缀(前导)
println(“withPrefix:以:id=“+this.id+”,size=“+this.size+”,this=“+this结尾)
ret
}
覆盖def更新(s:String,elem:T)={
println(“更新:this before with prefix:id=“+this.id+”,size=“+this.size+”,return=“+this”)
val pm=带前缀
println(“更新:返回到更新的前缀:id=“+pm.id+”,size=“+pm.size+”,return=“+pm”)
println(“=>update:this-after-withPrefix-to-pm.value:id=“+this.id+”,size=“+this.size+”,return=“+this”)
pm.value=一些(元素)
println(“==>更新:此在协助pm之后。值:id=“+this.id+”,size=“+this.size+”,return=“+this)
}
覆盖def删除(s:字符串):选项[T]=
如果(s.isEmpty){val prev=value;value=None;prev}
else后缀获取s(0)flatMap(u.remove(s子字符串1))
def迭代器:迭代器[(字符串,T)]=
(第0节)
地图(a->0)
因此,问题是:更新方法中带有“pm.value=Some(elem)”的行如何可能导致PrefixMap的继承映射更新为(a->0)?不清楚您所说的“PrefixMap的继承映射”是什么意思Map
是一种trait
,如果您来自Java世界,它类似于接口
。这意味着Map
本身没有任何价值,它只是指定契约,并通过“核心”方法提供各种便利方法的一些默认实现(您在前缀映射中实现的那些)
至于整个数据结构是如何工作的,您应该将这个PrefixMap
实现想象为一个。从逻辑上讲,每个边都有一个单独的字符(在前缀序列中),每个节点都可能有一个对应于字符串的值,该字符串是通过在从根节点到当前节点的过程中累积所有字符而创建的
因此,如果您有一个带有“ab”->12
键值的映射,那么树将如下所示:
如果您将“ac”->123
添加到树中,它将成为
最后,如果将“a”->1
添加到树中,它将成为:
这里的重要观察结果是,如果将“a”节点作为根,那么剩下的将是一个有效的前缀树,其中所有字符串都由该“a”前缀缩短
实际布局有点不同:
有一个根节点是PrefixMap[T]
,从外部是Map[String,T]
,还有一个用于空字符串键的节点
内部节点是值
+后缀
,即可选值和子节点的合并列表,其边缘上有相应的字符,形成映射[Char,PrefixMap[T].
正如您所看到的,update
实现是有效地使用withPrefix
调用并为其赋值。那么withPrefix
方法做什么呢?虽然它是递归实现的,但可能更容易用迭代的方式来考虑它。从这个角度来看,它迭代字符一个接一个地删除给定字符串
,并在树中导航以创建缺少的节点请参见
case None=>
后缀=后缀+(前导->空)
最后返回与整个字符串
对应的节点(即,如果最深的递归s.isEmpty
,则返回此
)
方法get
的实现实际上与withPrefix
非常相似:它递归地迭代给定的字符串并在树中导航,但它更简单,因为它不必创建缺少的节点。因为子节点实际上也存储在Map
itsget
方法返回Option
同样的方法PrefixMap
应该返回Option
。因此您可以使用flatMap
,如果在某个级别上没有这样的子节点,它将正常工作
最后,iterator
将其迭代器创建为
value.iterator
(Scala中的选项
实现了iterator
,它根据是否有值只返回1或0个元素)
所有子节点的所有迭代器
s只将其自身的字符作为前缀添加到其键中
所以当你这么做的时候
val pm = new PrefixMap[Int]
pm.update("a", 0)
println(pm)
update
在树中创建are节点并存储值。而pm.toString
实际上使用iterate
来构建字符串表示。因此它在树集合中迭代所有节点中非空的value
选项中的所有值。很漂亮,谢谢“PrefixMap的继承映射”我指的是PrefixMap本身就是一个映射,与它引用的映射(后缀)不同。我主要错过的是理解iteraror实现,这就是为什么我对简单的值分配在PrefixMap中生成键值映射感到惊讶。感谢您的清晰解释!