2012-11-28 3 views
5

맵과 비슷한 새로운 유형 인 청크를 구현하려고합니다. 기본적으로 "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") 

내가 가진이 주로 나는 + 연산자는 불변지도를 위해 작동하는 방법에 의해 조금 혼란 스러워요 것을 제외하고, 작업.

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

, 일반적으로이 구현은 적절한 지 여부에 대한 의견이 극명하게 될 것이다 : 여기

내가 지금 가지고있는 것입니다.

감사합니다.

편집 : 대수 데이터 형식 솔루션이 우수하지만 한 가지 문제가 남아 있습니다.

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는 어떤 종류의 추상 클래스/특성을 봉인해야합니다. 나에게 열려있는 질문은 어떤 종류의 기능이이 수퍼 클래스에 포함되어야하는지이다. 일반적으로 Map이나 String처럼 행동해야합니까? 이 점에서 질문은 나에게 완전히 명확하지 않습니다 ... – bluenote10

관련 문제