2011-07-05 1 views
4

내가 반환하는 함수 (그루비 코드) 스칼라에서스칼라지도

[words: "one two", row: 23, col: 45] 

내가 스칼라지도에 위의 변경하지만 내가

Map[String, Any] 

로 선언하도록 강요하고이 값 그러나 이것은 내가 ("단어") 키를 를 같은 지도에 액세스하는 경우 나 상용구

map2("words").asInstanceOf[String] 
을 추가해야한다는 단점이있다

asInstanceOf를 추가 할 필요가없는 더 나은 방법이 scala에 있습니까?

답변

10

정적 타이핑의 주조 및 혜택을 방지하기 위해, 당신은 튜플 (String, Int, Int) 반환 할 수 있습니다 :

def getResult = ("one two", 23, 45) 

val res = getResult 
res._1 // the line 

// alternatively use the extractor 
val (line, row, _) = getResult // col is discarded 
line // the line 
row // the row 

또는 결과의 경우 클래스를 사용

case class MyResult(line: String, row: Int, col: Int) 

def getResult = MyResult("one two", 23, 45) 

val res = getResult 
res.line // the line 

// alternatively use the extractor provided by the case class 
val MyResult(line, row, _) = getResult // col is discarded 
line // the line 
row // the row 

나는 것 필드 이름이 지정되고 실제로는 한 줄만 더 많기 때문에 사례 클래스를 선호합니다.

0

편집 : 난 당신처럼 그지도를 가지고 그것으로 더 깨끗하게 인터페이스 할 수있는 방법이 필요하다고 이해했다. 케이스 클래스 접근법은, 적용 가능하다면, 내가 아래에서 제안하고있는 것보다 우수합니다. Either 유형을 사용할 수 있도록 할 당신의 예에서와 같이 두 개의 가능한 값 유형을 갖는

class TypedKey[T] { 
    def name = { 
    // assumes you declare only `object` instances 
    val simpleName = getClass.getSimpleName 
    val moduleName = if (simpleName.endsWith("$")) simpleName.substring(0, simpleName.size - 1) else simpleName 
    val lastDollar = moduleName.lastIndexOf('$') 
    if (lastDollar == -1) moduleName else moduleName.substring(lastDollar + 1) 
    } 
} 

object RubyKeys { 
    object words extends TypedKey[String] 
    object row extends TypedKey[Int] 
    object col extends TypedKey[Int] 
} 

class MapWrapper(val underlying: Map[String, Any]) { 
    def apply[T](key: TypedKey[T]) = underlying(key.name).asInstanceOf[T] 
} 

def main(args: Array[String]) { 

    val map = Map("words" -> "one two", "row" -> 23, "col" -> 45) 
    val wrapper = new MapWrapper(map) 

    import RubyKeys._ 

    val w = wrapper(words) // String 
    val r = wrapper(row) // Int 
    val c = wrapper(col) // Int 
    println(w, r, c) 
} 
0

: 당신의 키가 항상 같은 값 형식에 매핑하는 경우


, 당신이 뭔가를 할 수 있습니다 하위 유형 LeftRight로 : 당신이지도에서 다시 값을받을 경우

val m = Map("words" -> Left("one two"), "rows"-> Right(23), "cols"-> Right(45)) 

, 당신은, 당신이 확인할 수 있습니다 예 : 패턴 일치 또는 isLeftisRight을 사용하고 그에 따라 "unwrap"합니다.

6

여기가 학급이 친구 인 경우입니다. 지도의 키가 사례 클래스 인 경우 클라이언트 코드가 해당 유형을 올바르게 처리하도록하고 강제로 모든 유형을 올바르게 처리하도록 할 수 있습니다.

 S:\>scala 
    Welcome to Scala version 2.9.0.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_25). 
    Type in expressions to have them evaluated. 
    Type :help for more information. 

    scala> sealed abstract class Thing; 
    defined class Thing 

    scala> case class Toaster(slices: Int) extends Thing; 
    defined class Toaster 

    scala> case class Bucket(contents: String) extends Thing; 
    defined class Bucket 

    scala> val things = Map("toasty" -> Toaster(2), "buck" -> Bucket("stuff")); 
things: scala.collection.immutable.Map[java.lang.String,Product with Serializable with Thing] = Map(toasty -> Toaster(2), buck -> Bucket(stu 
ff)) 

scala> for (x <- things) x match { 
    case (k,Toaster(s)) => println(k + " " + s) 
    case (k,Bucket(c)) => println(k + " " + c) 
    } 
toasty 2 
buck stuff 

여기의 핵심은 match 문이 다양한 경우를 제거하고 올바르게 입력 된 변수를 사용하여 필드를 일치시키는 것입니다. abstract 클래스를 sealed로 선언함으로써 컴파일러가 모든 사용 가능한 하위 클래스를 가지고 있음을 알립니다. 이 정보를 통해 사례가 누락 된 경우이를 알 수 있으며 추가 최적화 작업을 수행 할 수도 있습니다.