2012-11-28 13 views
5

マップに似た新しいタイプのチャンクを実装しようとしています。基本的に、 "Chunk"はString - > Chunkのマッピングか文字列そのものです。scalaカスタムマップ

例:このように動作することができるはずです。私はこのほとんどが、私は+演算子は、不変のマップのためにどのように機能するかによって少し混乱していますことを除いて、働いている

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

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

、一般的にこの実装が適切であるかどうかについてのコメントをいただければ幸いです。ここ

は、私が今持っているものです。

ありがとうございます!

編集:代数データ型のソリューションは優れていますが、1つの問題が残ります。

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の何かを返すように望んでいますか?これは、次の問題が発生して失敗します。

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

EDIT2: Xiefeiこの質問答え - 拡張マップがこれを実行するために、私はを持っている必要がありますので、私は、チャンクのスーパータイプ(B1)と+取り扱う必要がありますいくつかのそのための実装なので、これで十分でしょう:

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

をしかし、私が今まで本当にそのいずれかを使用する予定はありませんが、その代わり、私は次のようにチャンクを返す私の実装が含まれます

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

'+'の実装は、不変のマップの場合、追加されたキー/値で新しいマップを返す必要がありますか?あなたはすでにMap( '_map')を 'ラップ'しているので、' + 'の実装のために' _map'に委譲するだけで動作します:def + [B1>:Chunk](kv:(String、B1)) = _map + kv'となる。本当の問題は、「単純な」チャンク(それはちょうどストリングであるもの)にとっては意味がないということです。つまり、上で説明したコンストラクタのセットを持つと、 '+'を実装すると、 'Chunk'の定義が破られます。なぜなら、String-Chunkを// Map-チャンク。 – Faiz

答えて

1

継承の代わりに合成を使用したことはありますか?したがって、Chunkを直接Map [String、Chunk]に拡張する代わりに、Chunkに内部的にMap [String、Chunk]のインスタンスを保持させ、必要な追加メソッドを提供したり、内部マップのメソッドに委譲したりするだけです。あなたが必要なもの

+1

私はこれについて考えましたが、それはかなり良い点ですが、私は地図を拡張することで無料で含まれるすべてのグッズによって誘惑されました。 – mattomatic

1
def +(kv: (String, Chunk)):Chunk = new Chunk(_map + kv, _value) 
override def +[B1 >: Chunk](kv: (String, B1)) = _map + kv 

は新しい+方法であり、また、Map特性で宣言されたものを実装しています。

2

書かれているとおり、MapStringの両方を同時に指定することはできません。私は何でも便利な方法をEitherを使用して値をキャプチャし、追加することを見ていることでしょう、あなたは必要です。また、あなたが本当にそのようにキー/値のペアを追加するような状況で何をする必要があるかについて考えることを強制されます

case class Chunk(value:Either[Map[String,Chunk],String]) { 
    ... 
} 

Stringを表すChunkです。

5

Algebraic data typeのアプローチはありますか?あなたは次のように使用することができます

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

    } 

unapply抽出したばかりの提案です

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 
} 

。うまくいけば、あなたはあなたが望むものを得るまでこのアイデアを混乱させることができます。

+2

+1 * "基本的に、チャンクはString - > Chunkのマッピングか文字列そのものです" * imhoはある種の密封抽象クラス/特性を要求します。私にとってオープンな質問は、このスーパークラスにどのような機能を組み込むべきかということです。それは一般的にマップや文字列のように動作する必要がありますか?これに関して、質問は私に完全にはっきりしていません... – bluenote10

関連する問題