我有以下列表:
val lst: List[Char] = //...
我想在模式匹配中使用它如下:
lst match {
case firstPart :: '|' :: theRestOfTheList =>
//do something with them
}
问题是firstPart
被视为单个字符。但我希望它在第一个'|'
之前成为列表的一部分。
是否可以在Scala中以简洁的方式这样做?
是的,使用自定义提取器。
scala> val str: List[Char] = "foo|bar".toList
str: List[Char] = List(f, o, o, |, b, a, r)
scala> :paste
// Entering paste mode (ctrl-D to finish)
object SuperSplit {
def unapply(list: List[Char]): Option[(List[Char], List[Char])] = {
val (a, b) = list.splitAt(list.indexOf('|'))
Some((a, b.tail))
}
}
// Exiting paste mode, now interpreting.
defined object SuperSplit
scala> str match { case SuperSplit(a, b) => println(s"$a $b")}
List(f, o, o) List(b, a, r)
警告:处理列表为空的边角情况和其他情况
特殊语法
scala> :paste
// Entering paste mode (ctrl-D to finish)
object `|` {
def unapply(list: List[Char]): Option[(List[Char], List[Char])] = {
val (a, b) = list.splitAt(list.indexOf('|'))
Some((a, b.tail))
}
}
// Exiting paste mode, now interpreting.
defined object $bar
scala> str match { case `|`(a, b) => println(s"$a $b")}
List(f, o, o) List(b, a, r)
还有另一种方法可以做到这一点,如果你可以在字符串中转换字符列表然后将其与正则表达式匹配 - 我假设你有一个字符串的原始字符列表。无论如何,这是解决方案:
val pattern = """(.*)\|(.*)""".r
lst.mkString match {
case pattern(left, right) => // do something with left & right strings
case _ => // do something else
}
希望有所帮助!
这听起来像span几乎是你想要的,它将列表分成满足一些谓词和列表其余部分的最长前缀:
val (firstPart, secondPart) = lst.span(_ != '|')
需要注意的是,secondPart
将|
作为第一个元素,所以你的“真正的”第二部分将是secondPart.tail
。