Vil*_*tas 42 scala pattern-matching
我发现自己经常写这样的东西:
a match {
case `b` => // do stuff
case _ => // do nothing
}
Run Code Online (Sandbox Code Playgroud)
是否有更短的方法来检查某个值是否与模式匹配?我的意思是,在这种情况下我可以写if (a == b) // do stuff,但如果模式更复杂怎么办?就像匹配列表或任意复杂的任何模式时一样.我希望能够写出这样的东西:
if (a matches b) // do stuff
Run Code Online (Sandbox Code Playgroud)
我对Scala比较陌生,所以请原谅,如果我错过了大的东西:)
psp*_*psp 63
这正是我写这些函数的原因,因为没有人提到它们,这些函数显然令人印象深刻.
scala> import PartialFunction._
import PartialFunction._
scala> cond("abc") { case "def" => true }
res0: Boolean = false
scala> condOpt("abc") { case x if x.length == 3 => x + x }
res1: Option[java.lang.String] = Some(abcabc)
scala> condOpt("abc") { case x if x.length == 4 => x + x }
res2: Option[java.lang.String] = None
Run Code Online (Sandbox Code Playgroud)
Mad*_*doc 12
matchScala中的运算符在功能样式中使用时功能最强大.这意味着,不是在case语句中"做某事",而是返回一个有用的值.以下是命令式样式的示例:
var value:Int = 23
val command:String = ... // we get this from somewhere
command match {
case "duplicate" => value = value * 2
case "negate" => value = -value
case "increment" => value = value + 1
// etc.
case _ => // do nothing
}
println("Result: " + value)
Run Code Online (Sandbox Code Playgroud)
可以理解的是,上面的"无所事事"有点伤害,因为它似乎是超级丰富的.然而,这是因为以上是以命令式的方式写的.虽然这些结构有时可能是必要的,但在许多情况下,您可以将代码重构为功能样式:
val value:Int = 23
val command:String = ... // we get this from somewhere
val result:Int = command match {
case "duplicate" => value * 2
case "negate" => -value
case "increment" => value + 1
// etc.
case _ => value
}
println("Result: " + result)
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您可以将整个match语句用作值,例如,可以将其赋值给变量.并且更明显的是,match声明必须在任何情况下返回值; 如果最后一种情况会丢失,编译器就不能只做出一些事情.
这是一个品味问题,但一些开发人员认为这种风格更透明,更容易处理更真实的例子.我敢打赌,Scala编程语言的发明者在考虑更多功能时使用,如果你只需要决定是否需要采取某种行动,那么match这种if说法确实更有意义.(另一方面,你也可以if在功能方面使用,因为它也有一个返回值......)
Dan*_*ral 12
这可能有所帮助:
class Matches(m: Any) {
def matches[R](f: PartialFunction[Any, R]) { if (f.isDefinedAt(m)) f(m) }
}
implicit def any2matches(m: Any) = new Matches(m)
scala> 'c' matches { case x: Int => println("Int") }
scala> 2 matches { case x: Int => println("Int") }
Int
Run Code Online (Sandbox Code Playgroud)
现在,对问题的一般性质进行一些解释.
有三个地方,模式匹配可能发生:val,case和for.它们的规则是:
// throws an exception if it fails
val pattern = value
// filters for pattern, but pattern cannot be "identifier: Type",
// though that can be replaced by "id1 @ (id2: Type)" for the same effect
for (pattern <- object providing map/flatMap/filter/withFilter/foreach) ...
// throws an exception if none of the cases match
value match { case ... => ... }
Run Code Online (Sandbox Code Playgroud)
然而,还有另一种case可能出现的情况,即功能和部分功能文字.例如:
val f: Any => Unit = { case i: Int => println(i) }
val pf: PartialFunction[Any, Unit] = { case i: Int => println(i) }
Run Code Online (Sandbox Code Playgroud)
如果使用与任何case语句都不匹配的参数调用,函数和部分函数都将抛出异常.但是,部分函数还提供了一个方法isDefinedAt,可以测试是否可以进行匹配,以及调用的方法lift,它将a PartialFunction[T, R]转换为a Function[T, Option[R]],这意味着将导致非匹配值None而不是抛出异常.
匹配是许多不同测试的组合:
// assign anything to x
case x
// only accepts values of type X
case x: X
// only accepts values matches by pattern
case x @ pattern
// only accepts a value equal to the value X (upper case here makes a difference)
case X
// only accepts a value equal to the value of x
case `x`
// only accept a tuple of the same arity
case (x, y, ..., z)
// only accepts if extractor(value) returns true of Some(Seq()) (some empty sequence)
case extractor()
// only accepts if extractor(value) returns Some something
case extractor(x)
// only accepts if extractor(value) returns Some Seq or Tuple of the same arity
case extractor(x, y, ..., z)
// only accepts if extractor(value) returns Some Tuple2 or Some Seq with arity 2
case x extractor y
// accepts if any of the patterns is accepted (patterns may not contain assignable identifiers)
case x | y | ... | z
Run Code Online (Sandbox Code Playgroud)
现在,提取器是方法,unapply或者unapplySeq第一个返回,Boolean或者Option[T]第二个返回Option[Seq[T]],这None意味着没有匹配,Some(result)并将尝试匹配result,如上所述.
因此,这里有各种语法替代方案,如果不使用模式匹配可能发生的三种结构中的一种,这是不可能的.您可以模拟一些功能,例如值相等和提取器,但不是所有功能.
模式也可用于表达式.你的代码示例
a match {
case b => // do stuff
case _ => // do nothing
}
Run Code Online (Sandbox Code Playgroud)
然后可以表达为
for(b <- Some(a)) //do stuff
Run Code Online (Sandbox Code Playgroud)
诀窍是包装一个使其成为有效的枚举器.例如,列表(a)也可以使用,但我认为某些(a)最接近您的预期含义.
我能想到的最好的是:
def matches[A](a:A)(f:PartialFunction[A, Unit]) = f.isDefinedAt(a)
if (matches(a){case ... =>}) {
//do stuff
}
Run Code Online (Sandbox Code Playgroud)
这不会赢得任何风格点.
| 归档时间: |
|
| 查看次数: |
14161 次 |
| 最近记录: |