Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala:当两项中的一项满足某些条件时进行模式匹配_Scala_Pattern Matching_Extractor - Fatal编程技术网

Scala:当两项中的一项满足某些条件时进行模式匹配

Scala:当两项中的一项满足某些条件时进行模式匹配,scala,pattern-matching,extractor,Scala,Pattern Matching,Extractor,我经常编写代码来比较两个对象,并根据它们是相同的还是不同的,以及它们的不同程度来生成一个值 所以我可以写: val result = (v1,v2) match { case (Some(value1), Some(value2)) => "a" case (Some(value), None)) => "b" case (None, Some(value)) => "b" case _ = > "c" } 第二个和第三个案例实际上是一样的,所以我试着写

我经常编写代码来比较两个对象,并根据它们是相同的还是不同的,以及它们的不同程度来生成一个值

所以我可以写:

val result = (v1,v2) match {
  case (Some(value1), Some(value2)) => "a"
  case (Some(value), None)) => "b"
  case (None, Some(value)) => "b"
  case _ = > "c"
}
第二个和第三个案例实际上是一样的,所以我试着写:

val result = (v1,v2) match {
  case (Some(value1), Some(value2)) => "a"
  case (Some(value), None)) || (None, Some(value)) => "b"
  case _ = > "c"
}
但是没有运气

我在一些地方遇到了这个问题,这只是一个具体的例子,更一般的模式是我有两件事,我想知道它们中是否有一件,而且只有一件符合某个谓词,所以我想这样写:

val result = (v1,v2) match {
  case (Some(value1), Some(value2)) => "a"
  case OneAndOnlyOne(value, v: Option[Foo] => v.isDefined ) => "b"
  case _ = > "c"
}
filteredMatch(v1,v2)(_ %2 == 0){
    case List(value1, value2) => "a"
    case List(value) => "b"
    case _ => "c"
}
因此,这里的想法是,可以使用谓词(在本例中定义)配置OneAndOnlyOne,并且您可以在多个位置使用它

上面的方法根本不起作用,因为它是向后的,谓词需要传递到提取器,而不是返回

像这样的怎么样

val result = (v1,v2) match {
  case (Some(value1), Some(value2)) => "a"
  case new OneAndOnlyOne(v: Option[Foo] => v.isDefined )(value) => "b"
  case _ = > "c"
}
与:

但是,这不是编译

有人能想出一个办法让这个解决方案奏效吗?还是提出另一个解决方案?我可能把事情弄得更复杂了:)

这个怎么样:

    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>

如果首先将其定义为val,则应该能够执行此操作:

val MyValThatIsCapitalized = new OneAndOnlyOne(v: Option[Foo] => v.isDefined )
val result = (v1,v2) match {
  case (Some(value1), Some(value2)) => "a"
  case MyValThatIsCapitalized(value) => "b"
  case _ = > "c"
}

正如名称所暗示的那样,包含提取器对象的val的名称必须大写。

我想你问的是两个稍微不同的问题

一个问题是如何在switch语句中使用“or”不起作用做在这种情况下,您不能使用变量(因为通常情况下,它们可能匹配不同的类型,这会导致类型混淆)。因此:

另一个问题是如何避免反复执行此操作,特别是如果您希望能够获取元组中的值。我在这里为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"
}
在Scala 2.8上:

val result = List(v1,v2).flatten match {
  case List(value1, value2) => "a"
  case List(value) => "b"
  case _ = > "c"
}
然而,在Scala2.7上,您需要一个类型提示来使其工作。因此,假设
value
Int
,例如,那么:

val result = (List(v1,v2).flatten : List[Int]) match {
  case List(value1, value2) => "a"
  case List(value) => "b"
  case _ = > "c"
}

有趣的是,我把答案上的“第一个”误读为“列表”,这让我产生了这个想法。:-)

如果必须支持任意谓词,则可以从中派生(基于):

函数的定义:

def filteredMatch[T,R](values : T*)(f : T => Boolean)(p: PartialFunction[List[T], R]) : R = 
    p(List((values filter f) :_* ))
现在您可以这样使用它:

val result = (v1,v2) match {
  case (Some(value1), Some(value2)) => "a"
  case OneAndOnlyOne(value, v: Option[Foo] => v.isDefined ) => "b"
  case _ = > "c"
}
filteredMatch(v1,v2)(_ %2 == 0){
    case List(value1, value2) => "a"
    case List(value) => "b"
    case _ => "c"
}
我不太确定这是否是一个好主意(即可读性)。但这是一个巧妙的练习


如果您可以匹配元组:
case(value1,value2)=>…
而不是列表,那就太好了。

因为您已经匹配了(一些(x),一些(y)),您可以显式匹配(无,无),剩下的案例是(一些(x),无)和(无,一些(y)):


正则表达式作为case的用法是一样的。谢谢Mitch,我确实试过了,我想它失败了,因为我的val没有大写。。有意思。你有一个用例来说明你为什么要这么做吗?也许使用
或者
用例存在更好的解决方案-我主要是想避免编写这两个用例,例如(一些,没有)和(没有,一些)。我的通用用例是,我正在比较两个产品的一个特定功能,可能两个产品都有该功能,或者只有一个,或者如果它们都有,可能其中一个对该功能有很好的价值,而另一个价值很低。可能重复感谢Daniel的回答,这看起来不错,但只适用于谓词“x=>x.isDefined”,我不能用它来表示“x=>x%2==0”来检查这两项中是否有一项是偶数。@Alex-你可以这样表达:
List(v1,v2)filter(%2==0)match{case List(value1,value2)=>“a”case List(value)=>“b”case=>“c”)首先过滤列表。我认为Daniel的解决方案是最直接的。@Alex:我想通过一些工作,你可以提取模式:
def xMatch(values:List[T],f:T=>Boolean,p:List[PartialFunction[T,X]])
@Alex:我已经对它进行了一些修补:嗨,Rex,看起来很有希望,但它还没有扩展到其他情况,例如,其中一个不是要求定义其中一个,而是要求其中一个说“是偶数”或“值大于10”。是不是:case(Some(x),Some(y)),如果((x>10)&(y isEven))=>“两者”都起作用?我不确定我是否在跟踪Jim,但是:是的,这确实起作用,但我不认为这是我要说的。我想在概念上这样做:Case(oneisEven)=>Case(bothAreEven)=>。例如,它们是否相等只是一个不同的测试,而不是它们是否都没有。这看起来很简单,我想我在Scala 2.7中试过,但它没有编译,我会再试一次。伙计,我喜欢Scala。它的可读性再好不过了,它是一个函数。还有一艘客轮。
filteredMatch(v1,v2)(_ %2 == 0){
    case List(value1, value2) => "a"
    case List(value) => "b"
    case _ => "c"
}
def decide [T](v1: Option[T], v2:Option[T]) = (v1, v2) match {
  case (Some (x), Some (y)) => "a"
  case (None, None)         => "c"
  case _                    => "b"
}

val ni : Option [Int] = None 
decide (ni, ni)            // c
decide (Some (4), Some(3)) // a
decide (ni, Some (3))      // b
decide (Some (4), ni)      // b