我的配置值与地图中的某个值匹配,并且根据匹配的值,我采取了操作。以下是我正在尝试做的一些示例代码
val x = 1 // or 2 or 3
val config = Map("c1"-> 1, "c2"-> 2, "c3"-> 3)
x match {
case config("c1") =>
println("1")
case config("c2") =>
println("2")
case config("c3") =>
println("3")
}
现在这应打印1
,因为config("c1")
评估为1
,但它会出错
error: value config is not a case class, nor does it have an unapply/unapplySeq member
case config("c1") =>
同样适用于其他2例。我为什么要在这里不申请?有什么指针吗?
答案 0 :(得分:3)
这样的表达式看起来像extractor,因此有关unapply/unapplySeq
方法的消息。如果您不想使用提取器但只想匹配普通值,则需要将该值存储在稳定的标识符中 - 您不能将任意表达式用作匹配大小写:
val case1 = config("c1")
x match {
case case1 => println("1")
...
}
答案 1 :(得分:2)
据我所知,在Scala中,x match {case config("c1")
被转换为config.unapply(x)
,其分支取决于unapply方法的结果。正如 Imm 在他的回答中已经提到的那样,稳定标识符(文字和val
)的情况并非如此,我鼓励您使用他的解决方案。
尽管如此,为了向您展示如何使用提取器解决问题,我想发布一个不同的解决方案:
def main(args: Array[String]): Unit = {
object config {
val configData = Map("c1" -> 1, "c2" -> 2, "c3" -> 3)
def unapply(value: Int): Option[String] = configData find (_._2 == value) map (_._1)
}
1 to 4 foreach {
case config("c1") => println("1")
case config("c2") => println("2")
case config("c3") => println("3")
case _ => println("no match")
}
}
我更改了match
foreach
以显示不同的结果,但这对实施没有影响。这将打印出来:
1
2
3
no match
如您所见,case config("c1")
现在调用unapply方法并检查结果是否为Some("c1")
。请注意,这与您使用地图的方式相反:根据值搜索密钥。但是,这是有道理的:如果在地图中,"c1"
和"c2"
都映射到1
,则1
与两者匹配,_
匹配所有内容的方式相同,在我们的例子中,即使4
未配置。
这里也是一个非常简短的tutorial on extractors。我发现它并不是特别好,因为返回的类型和参数类型都是Int
,但它可能有助于您了解正在发生的事情。
答案 2 :(得分:1)
正如其他人所说,使用x match { case config("c1") => ...
,scala会查找名为config
的提取器(带有unapply
方法的内容,该方法采用单个值并返回Optional值) ;以这种方式进行模式匹配似乎是对模式的滥用,我不会为此使用提取器。
就个人而言,我会推荐以下其中一项:
if (x == config("c1"))
println("1")
else if (x == config("c2"))
println("2")
else ...
或者,如果您使用匹配语句设置,则可以使用以下条件:
x match {
case _ if x == config("c1") =>
println("1")
case _ if x == config("c2") =>
println("2")
case _ if x == config("c3") =>
println("3")
}
不那么干净;遗憾的是,没有一种方法可以在提取器的字面上调用方法调用。您可以使用反向标记来告诉scala"匹配此变量的值" (而不是默认行为,它将产生名为该变量的值):
val (c1,c2,c3) = (config("c1"), config("c2"), config("c3"))
x match {
case `c1` =>
println("1")
case `c2` =>
println("2")
case `c3` =>
println("3")
}
最后,如果你的目标是反向应用地图,可以试试这个吗?
scala> Map("a" -> 1).map { case (k,v) => (v,k) }
res0: scala.collection.immutable.Map[Int,String] = Map(1 -> a)