Ale*_*ack 10 scala pattern-matching extractor
I'm often writing code that compares two objects and produces a value based on whether they are the same, or different, based on how they are different.
So I might write:
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case (Some(value), None)) => "b"
case (None, Some(value)) => "b"
case _ = > "c"
}
Run Code Online (Sandbox Code Playgroud)
Those 2nd and 3rd cases are the same really, so I tried writing:
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case (Some(value), None)) || (None, Some(value)) => "b"
case _ = > "c"
}
Run Code Online (Sandbox Code Playgroud)
But no luck.
我在一些地方遇到这个问题,这只是一个具体的例子,更一般的模式是我有两件事,我想知道他们中是否只有一个遇到一些谓词,所以我想写这样的事情:
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case OneAndOnlyOne(value, v: Option[Foo] => v.isDefined ) => "b"
case _ = > "c"
}
Run Code Online (Sandbox Code Playgroud)
所以这里的想法是OneAndOnlyOne可以配置一个谓词(在这种情况下是isDefined),你可以在多个地方使用它.
以上内容根本不起作用,因为它的向后,谓词需要传递给提取器而不返回.
这样的事怎么样?
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case new OneAndOnlyOne(v: Option[Foo] => v.isDefined )(value) => "b"
case _ = > "c"
}
Run Code Online (Sandbox Code Playgroud)
有:
class OneAndOnlyOne[T](predicate: T => Boolean) {
def unapply( pair: Pair[T,T] ): Option[T] = {
val (item1,item2) = pair
val v1 = predicate(item1)
val v2 = predicate(item2)
if ( v1 != v2 )
Some( if ( v1 ) item1 else item2 )
else
None
}
}
Run Code Online (Sandbox Code Playgroud)
但是,这不编译.
谁能看到让这个解决方案有效的方法?或提出另一种解决方案 我可能比这更复杂:)
Rex*_*err 19
我想你问两个略有不同的问题.
一个问题是如何在switch语句中使用"或".|| 不起作用; | 确实.在这种情况下你不能使用变量(因为通常它们可能匹配不同的类型,这会使类型混乱).所以:
def matcher[T](a: (T,T)) = {
a match {
case (Some(x),Some(y)) => "both"
case (Some(_),None) | (None,Some(_)) => "either"
case _ => "none"
}
}
Run Code Online (Sandbox Code Playgroud)
另一个问题是如何避免不得不一遍又一遍地执行此操作,尤其是如果您希望能够获得元组中的值.我在这里为Option实现了一个版本,但你可以使用一个解包的元组和一个布尔值.
实现此目的的一个技巧是在开始匹配之前预先打包值,然后使用您自己的匹配结构来执行您想要的操作.例如,
class DiOption[+T] {
def trinary = this
}
case class Both[T](first: T, second:T) extends DiOption[T] { }
case class OneOf[T](it: T) extends DiOption[T] { }
case class Neither() extends DiOption[Nothing] { }
implicit def sometuple2dioption[T](t2: (Option[T],Option[T])): DiOption[T] = {
t2 match {
case (Some(x),Some(y)) => Both(x,y)
case (Some(x),None) => OneOf(x)
case (None,Some(y)) => OneOf(y)
case _ => Neither()
}
}
// Example usage
val a = (Some("This"),None)
a trinary match {
case Both(s,t) => "Both"
case OneOf(s) => "Just one"
case _ => "Nothing"
}
Run Code Online (Sandbox Code Playgroud)
如果你必须支持任意谓词,你可以从中得出(这是基于Daniel的想法):
List(v1, v2) filter (_ %2 == 0) match {
case List(value1, value2) => "a"
case List(value) => "b"
case _ => "c"
}
Run Code Online (Sandbox Code Playgroud)
功能的定义:
def filteredMatch[T,R](values : T*)(f : T => Boolean)(p: PartialFunction[List[T], R]) : R =
p(List((values filter f) :_* ))
Run Code Online (Sandbox Code Playgroud)
现在您可以像这样使用它:
filteredMatch(v1,v2)(_ %2 == 0){
case List(value1, value2) => "a"
case List(value) => "b"
case _ => "c"
}
Run Code Online (Sandbox Code Playgroud)
我不太确定这是不是一个好主意(即可读).但是,尽管如此,这是一次巧妙的运动.
如果你能匹配元组,那就太好了:case (value1, value2) => ...而不是列表.
这个怎么样:
Welcome to Scala version 2.8.0.r20327-b20091230020149 (Java HotSpot(TM) Client VM, Java 1.6.0_17).
Type in expressions to have them evaluated.
Type :help for more information.
scala> def m(v1: Any,v2: Any) = (v1,v2) match {
| case (Some(x),Some(y)) => "a"
| case (Some(_),None) | (None,Some(_)) => "b"
| case _ => "c"
| }
m: (v1: Any,v2: Any)java.lang.String
scala> m(Some(1),Some(2))
res0: java.lang.String = a
scala> m(Some(1),None)
res1: java.lang.String = b
scala> m(None,None)
res2: java.lang.String = c
scala>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11568 次 |
| 最近记录: |