给出以下代码:
case class ChangeSet(field:String, from:Object, to:Object)
private var changed:List[ChangeSet] = Nil
def change(field:String, from:Object, to:Object) {
changed.find{ case ChangeSet(field,_,_) => true } match {
case Some(ChangeSet(field,to,_)) => // do stuff
case Some(_) => // do stuff
case _ => // do stuff
}
}
给我带来麻烦的一行是Some(ChangeSet(field,to,_))
。
它编译但似乎正在发生的事情是Scala将其填充为通配符的占位符。我的假设基于以下事实:当我执行以下Some(ChangeSet(field,to,to))
时,我收到错误to is already defined as value
。
我想要的是从方法参数中使用to
创建一个ChangeSet对象。
这可能吗?
答案 0 :(得分:7)
当模式匹配时,Scala会将所有以小写字母开头的标识符解释为占位符并填充值。要告诉Scala使用to
作为外部作用域的常量值,您需要使用反引号围绕它:`to`
。或者,您可以像Rex Kerr建议的那样将to
的名称更改为To
,但我更喜欢将变量保持为小写。
这应该有效:
def change(field:String, from:Object, to:Object) {
changed.find{ case ChangeSet(`field`,_,_) => true } match {
case Some(ChangeSet(`field`, `to`, _)) => // do stuff
case Some(_) => // do stuff
case _ => // do stuff
}
}
答案 1 :(得分:4)
这里似乎有两个混乱。第一个是Rex和Kim确定的那个。您可以从 Scala中的编程中阅读this section以获取更多信息。归结为:
x match { case Some(foo) => } // variable pattern, defines and binds variable foo
x match { case Some(Foo) => } // constant pattern, based on val Foo
x match { case Some(`foo`) => } // constant pattern for lowercase val
您还可以使用警卫来约束匹配
x match { case Some(foo) if condition => }
第二个困惑是你要“使用方法参数”创建一个ChangeSet对象。如果我理解正确,你试图使用case类语法构造一个对象:
ChangeSet(field, from, to)
这在模式匹配的那一方面不起作用。在模式匹配的 case 端发生的事情实际上可以看作是ChangeSet构造的 reverse 。 match { case ChangeSet(field, from, to) => }
有点解构您的ChangeSet
对象,并将其部分分配给field
,from
和to
个值。当它像这样组成时也是如此:Some(ChangeSet(field, from, to))
,它首先解构Some
然后ChangeSet
。您可以看到正在使用值定义,因为它正在利用相同的解构机制:
scala> val cset = ChangeSet("a", "from", "to")
cset: ChangeSet = ChangeSet(a,from,to)
scala> val Some(ChangeSet(s, o1, o2)) = Some(cset)
s: String = a
o1: java.lang.Object = from
o2: java.lang.Object = to
您希望做的是构建一个复制ChangeSet
的值但替换单个字段的新对象。 Case类支持copy
,继续我的REPL示例:
scala> val cset2 = cset.copy(from = o2)
cset2: ChangeSet = ChangeSet(a,to,to)
考虑到这一点,这是change
的另一个建议:
def change(field:String, from:Object, to:Object) {
changed.find(_.field == field) match {
case Some(cset) =>
val csetnew = cset.copy(from = to)
// do stuff with csetnew
case None =>
// do stuff
}
}
答案 2 :(得分:1)
您不能在这样的模式中使用变量名称。您必须先将其与新变量匹配,然后进行显式比较。
def change(field:String, from:Object, to:Object) {
changed.find{ case ChangeSet(f,_,_) => field == f } match {
case Some(ChangeSet(f,too,_)) if f == field && to == too => // do stuff
case Some(_) => // do stuff
case _ => // do stuff
}
}
答案 3 :(得分:1)
如果在模式匹配中使用小写名称,Scala将填写该值。如果您只想匹配该值,则需要使用大写名称。撇开你要做的事情的逻辑,以及名字排序的可疑变化,你想要:
def change(Field: String, from:Object, To: Object) {
changed.find{
case ChangeSet(Field,_,_) => true
case _ => false // You need this line! No match is an exception, not false!
} match {
case Some(ChangeSet(Field,To,_)) => // do stuff
case Some(_) => // do stuff
case _ => // do stuff
}
}