在Scala匿名函数中是否有更简洁的模式匹配方法?

时间:2011-06-23 17:49:52

标签: scala pattern-matching

我发现自己编写了如下代码:

val b = a map (entry =>
    entry match {
        case ((x,y), u) => ((y,x), u)
    }
)

我想用不同的方式写它,如果只有这个有效:

val c = a map (((x,y) -> u) =>
    (y,x) -> u
)

有什么方法可以让我接近这个吗?

4 个答案:

答案 0 :(得分:54)

信不信由你,这有效:

val b = List(1, 2)
b map({case 1 => "one"
       case 2 => "two"})

在简单的情况下,您可以跳过p => p match。所以这应该有效:

val c = a map {case ((x,y) -> u) =>
    (y,x) -> u
}

答案 1 :(得分:22)

在您的示例中,您可能会使用三种略有不同的语义。

  1. 映射集合,转换与模式匹配的每个元素。如果任何元素不匹配,则抛出异常。这些语义是通过

    实现的
    val b = a map { case ((x, y), u) => ((y, x), u) }
    
  2. 映射集合,转换与模式匹配的每个元素。无声地丢弃不匹配的元素:

    val b = a collect { case ((x, y), u) => ((y, x), u) }
    
  3. 映射集合,安全地解构,然后转换每个元素。这些是我希望像

    这样的表达式的语义
    val b = a map (((x, y), u) => ((y, x), u)))  
    

    不幸的是,在Scala中没有简洁的语法来实现这些语义。 相反,你必须自己解构:

    val b = a map { p => ((p._1._2, p._1._1), p._2) }
    

    有人可能想要使用值定义进行解构:

    val b = a map { p => val ((x,y), u) = p; ((y, x), u) }
    

    但是,此版本is no more safe than the one that uses explicit pattern matching。因此,如果您需要安全解构语义,最简洁的解决方案是显式键入您的集合以防止意外扩展并使用显式模式匹配:

    val a: List[((Int, Int), Int)] = // ...
    // ...
    val b = a map { case ((x, y), u) => ((y, x), u) }
    

    如果a的定义远离其使用(例如在单独的编译单元中),则可以通过在地图调用中归类其类型来最小化风险:

    val b = (a: List[((Int, Int), Int)]) map { case ((x, y), u) => ((y, x), u) }
    

答案 2 :(得分:10)

在你引用的例子中,最干净的解决方案是:

val xs = List((1,2)->3,(4,5)->6,(7,8)->9)
xs map { case (a,b) => (a.swap, b) }

答案 3 :(得分:4)

val b = a map { case ((x,y), u) => ((y,x), u) }