包含混合类型值的Scala映射

rjc*_*rjc 5 scala

我有一个返回的函数(groovy代码)

[words: "one two", row: 23, col: 45]
Run Code Online (Sandbox Code Playgroud)

在scala中,我将上面更改为scala Map,但后来我被迫将其声明为

Map[String, Any]
Run Code Online (Sandbox Code Playgroud)

但是这样做的缺点是,如果我访问一个键,例如map("words"),我必须添加样板

map2("words").asInstanceOf[String]
Run Code Online (Sandbox Code Playgroud)

在scala中是否有更好的方法不需要我添加asInstanceOf?

kas*_*ens 11

为了避免强制转换并从静态类型中获益,您可以返回一个元组(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
Run Code Online (Sandbox Code Playgroud)

或者为结果使用案例类:

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
Run Code Online (Sandbox Code Playgroud)

我更喜欢case类,因为字段是命名的,它实际上只是一行.


Ros*_*son 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
Run Code Online (Sandbox Code Playgroud)

这里的关键是匹配语句可以解决各种情况,并为您提供正确的类型变量以匹配其中的字段.通过声明抽象类是密封的,您可以让编译器知道它具有所有可用的子类.通过该信息,它可以告诉您何时丢失案例,并且还可以进行进一步优化.