我经常编写比较两个对象的代码,并根据它们是否相同或不同(根据它们的不同之处)生成一个值。
所以我可能会写:
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"
}
所以这里的想法是 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"
}
with:
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
}
}
但是,这不能编译。
任何人都可以找到使该解决方案发挥作用的方法吗?或者提出另一种解决方案?我可能让这件事变得更加复杂:)
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"
}
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"
}
But no luck.
I encounter this problem in a few places, and this is just a specific example, the more general pattern is I have two things, and I want to know if one and only one of them meet some predicate, so I'd like to write something like this:
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case OneAndOnlyOne(value, v: Option[Foo] => v.isDefined ) => "b"
case _ = > "c"
}
So the idea here is that OneAndOnlyOne can be configured with a predicated (isDefined in this case) and you can use it in multiple places.
The above doesn't work at all, since its backwards, the predicate needs to be passed into the extractor not returned.
How about something like this?
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case new OneAndOnlyOne(v: Option[Foo] => v.isDefined )(value) => "b"
case _ = > "c"
}
with:
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
}
}
But, this doesn't compile.
Can anyone see a way to make this solution work? Or propose another solution? I'm probably making this more complicated than it is :)
发布评论
评论(6)
我认为您在问两个略有不同的问题。
一个问题是如何在 switch 语句中使用“or”。 ||不起作用; |做。在这种情况下,您不能使用变量(因为通常它们可能匹配不同的类型,这会使类型变得混乱)。所以:
另一个问题是如何避免一遍又一遍地这样做,特别是如果您希望能够获取元组中的值。我在这里为 Option 实现了一个版本,但您可以使用未包装的元组和布尔值。
实现此目的的一个技巧是,在开始匹配值之前预先包装值,然后使用您自己的匹配结构来执行您想要的操作。例如,
I think you're asking two slightly different questions.
One question is how to use "or" in switch statements. || doesn't work; | does. And you can't use variables in that case (because in general they might match different types, which renders the type confusing). So:
Another question is how to avoid having to do this over and over, especially if you want to be able to get at the value in the tuple. I've implemented a version here for Option, but you could use an unwrapped tuple and a boolean.
One trick to achieve this is that to prewrap the values before you start matching on it, and then use your own matching constructs that do what you want. For instance,
如果您必须支持任意谓词,您可以从中派生(基于 丹尼尔的想法):
函数的定义:
现在你可以像这样使用它:
我不太确定这是否是一个好主意(即可读)。但这仍然是一个巧妙的练习。
如果您可以匹配元组,那就太好了:case (value1, value2) => ... 而不是列表。
If you have to support arbitrary predicates you can derive from this (which is based on Daniel's idea):
the definition of the function:
Now you can use it like this:
I'm not so sure if it's a good idea (i.e. readable). But a neat exercise nonetheless.
It would be nice if you could match on tuples:
case (value1, value2) => ...
instead of lists.这个怎么样:
How about this:
如果您首先将其定义为 val,您应该能够做到这一点:
正如名称所暗示的,包含提取器对象的 val 的名称必须大写。
You should be able to do it if you define it as a val first:
As implied by the name, the name of the val containing the extractor object must be capitalized.
在 Scala 2.8 上:
但是,在 Scala 2.7 上,您需要类型提示才能使其工作。因此,假设
value
是Int
,那么:有趣的是,我在 Mitch Blevins 回答,这给了我这个想法。 :-)
On Scala 2.8:
On Scala 2.7, however, you need a type hint to make it work. So, assuming
value
isInt
, for instance, then:The funny thing about it is that I misread "first" as "list" on Mitch Blevins answer, and that gave me this idea. :-)
由于您已经匹配了 (Some(x), Some(y)),因此您可以显式匹配 (None, None),其余情况为 (Some(x), None) 和 (None, Some(y)) :
Since you already matched against (Some(x), Some(y)), you may match against (None, None) explicitly, and the remaining cases are (Some(x), None) and (None, Some(y)):