我正在尝试实现一个类似于Map的新类型Chunk.基本上,"Chunk"可以是String - > Chunk的映射,也可以是字符串本身.
例如它应该能够像这样工作:
val m = new Chunk("some sort of value") // value chunk
assert(m.getValue == "some sort of value")
val n = new Chunk("key" -> new Chunk("value"), // nested chunks
"key2" -> new Chunk("value2"))
assert(n("key").getValue == "value")
assert(n("key2").getValue == "value2")
Run Code Online (Sandbox Code Playgroud)
我有这个大部分都在工作,除了我对+运算符如何为不可变映射工作有点困惑.
这就是我现在拥有的:
class Chunk(_map: Map[String, Chunk], _value: Option[String]) extends Map[String, Chunk] {
def this(items: (String, Chunk)*) = this(items.toMap, None)
def this(k: String) = this(new HashMap[String, Chunk], Option(k))
def this(m: Map[String, Chunk]) = this(m, None)
def +[B1 >: Chunk](kv: (String, B1)) = throw new Exception(":( do not know how to make this work")
def -(k: String) = new Chunk(_map - k, _value)
def get(k: String) = _map.get(k)
def iterator = _map.iterator
def getValue = _value.get
def hasValue = _value.isDefined
override def toString() = {
if (hasValue) getValue
else "Chunk(" + (for ((k, v) <- this) yield k + " -> " + v.toString).mkString(", ") + ")"
}
def serialize: String = {
if (hasValue) getValue
else "{" + (for ((k, v) <- this) yield k + "=" + v.serialize).mkString("|") + "}"
}
}
object main extends App {
val m = new Chunk("message_info" -> new Chunk("message_type" -> new Chunk("boom")))
val n = m + ("c" -> new Chunk("boom2"))
}
Run Code Online (Sandbox Code Playgroud)
此外,对于一般来说这种实施是否合适的评论将不胜感激.
谢谢!
编辑:代数数据类型解决方案非常好,但仍存在一个问题.
def +[B1 >: Chunk](kv: (String, B1)) = Chunk(m + kv) // compiler hates this
def -(k: String) = Chunk(m - k) // compiler is pretty satisfied with this
Run Code Online (Sandbox Code Playgroud)
这里的 - 运算符似乎有效,但+运算符真的要我返回B1类型的东西(我想)?它失败了,出现以下问题:
overloaded method value apply with alternatives: (map: Map[String,Chunk])MapChunk <and> (elems: (String, Chunk)*)MapChunk cannot be applied to (scala.collection.immutable.Map[String,B1])
Run Code Online (Sandbox Code Playgroud)
编辑2:谢飞回答了这个问题 - 扩展地图要求我使用Chunk的超类型(B1)处理+,所以为了做到这一点,我必须有一些实现,所以这就足够了:
def +[B1 >: Chunk](kv: (String, B1)) = m + kv
Run Code Online (Sandbox Code Playgroud)
不过,我从来没有真的打算就用它,相反,我会还包括我的实现,如下返回块:
def +(kv: (String, Chunk)):Chunk = Chunk(m + kv)
Run Code Online (Sandbox Code Playgroud)
如何使用代数数据类型方法?
abstract sealed class Chunk
case class MChunk(elems: (String, Chunk)*) extends Chunk with Map[String,Chunk] {
val m = Map[String, Chunk](elems:_*)
def +[B1 >: Chunk](kv: (String, B1)) = m + kv
def -(k: String) = m - k
def iterator = m.iterator
def get(s: String) = m.get(s)
}
case class SChunk(s: String) extends Chunk
// A 'Companion' object that provides 'constructors' and extractors..
object Chunk {
def apply(s: String) = SChunk(s)
def apply(elems: (String, Chunk)*) = MChunk(elems: _*)
// just a couple of ideas...
def unapply(sc: SChunk) = Option(sc).map(_.value)
def unapply(smc: (String, MChunk)) = smc match {
case (s, mc) => mc.get(s)
}
}
Run Code Online (Sandbox Code Playgroud)
您可以使用如下:
val simpleChunk = Chunk("a")
val nestedChunk = Chunk("b" -> Chunk("B"))
// Use extractors to get the values.
val Chunk(s) = simpleChunk // s will be the String "a"
val Chunk(c) = ("b" -> nestedChunk) // c will be a Chunk: Chunk("B")
val Chunk(c) = ("x" -> nestedChunk) // will throw a match error, because there's no "x"
// pattern matching:
("x" -> mc) match {
case Chunk(w) => Some(w)
case _ => None
}
Run Code Online (Sandbox Code Playgroud)
该unapply提取器只是一个建议; 希望你可以搞砸这个想法,直到你得到你想要的东西.
您是否考虑过使用组合而不是继承?因此,不要直接扩展 Map[String, Chunk],而是让 Chunk 在内部保留 Map[String, Chunk] 的实例并提供所需的额外方法,否则委托给内部映射的方法。