Scala自定义地图 [英] scala custom map

查看:21
本文介绍了Scala自定义地图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现一种类似于 Map 的新类型 Chunk.基本上,Chunk"要么是 String -> Chunk 的映射,要么是字符串本身.

I'm trying to implement a new type, Chunk, that is similar to a Map. Basically, a "Chunk" is either a mapping from String -> Chunk, or a string itself.

例如它应该能够像这样工作:

Eg it should be able to work like this:

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")

我有这个主要工作,除了我对 + 操作符如何用于不可变映射有点困惑.

I have this mostly working, except that I am a little confused by how the + operator works for immutable maps.

这是我现在所拥有的:

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"))
}

此外,我们将不胜感激,对这种实现总体上是否合适的评论.

Also, comments on whether in general this implementation is appropriate would be appreciated.

谢谢!

代数数据类型解决方案非常好,但仍然存在一个问题.

The algebraic data types solution is excellent, but there remains one issue.

def +[B1 >: Chunk](kv: (String, B1)) = Chunk(m + kv) // compiler hates this
def -(k: String) = Chunk(m - k) // compiler is pretty satisfied with this

这里的 - 操作符似乎有效,但 + 操作符真的希望我返回 B1 类型的东西(我认为)?它因以下问题而失败:

The - operator here seems to work, but the + operator really wants me to return something of type B1 (I think)? It fails with the following issue:

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])

谢飞回答了这个问题——扩展地图要求我使用 Chunk 的超类型 (B1) 处理 +,因此为了做到这一点,我必须有一些 实现,所以这就足够了:

Xiefei answered this question -- extending map requires that I handle + with a supertype (B1) of Chunk, so in order to do this I have to have some implementation for that, so this will suffice:

def +[B1 >: Chunk](kv: (String, B1)) = m + kv

然而,我从来没有真正打算使用那个,相反,我将包括我的实现,它返回一个块,如下所示:

However, I don't ever really intend to use that one, instead, I will also include my implementation that returns a chunk as follows:

def +(kv: (String, Chunk)):Chunk = Chunk(m + kv)

推荐答案

代数数据类型方法怎么样?

  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)
    }

  }

你可以像这样使用:

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 
} 

unapply 提取器只是一个建议;希望你能把这个想法搞砸,直到你得到你想要的.

The unapply extractors are just a suggestion; hopefully you can mess with this idea till you get what you want.

这篇关于Scala自定义地图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆