Given the following code:
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
}
}
The line giving me trouble is Some(ChangeSet(field,to,_))
.
It compiles but what seems to be happening is that Scala is filling it in as a placeholder for a wildcard. I base that assumption on the fact that when I do the following Some(ChangeSet(field,to,to))
I get the error to is already defined as value
.
What I wanted is to make a ChangeSet object with to
from the method parameters.
Is that possible?
class MatchError extends RuntimeExceptionThis class implements errors which are thrown whenever an object doesn't match any pattern of a pattern matching expression.
Scala's pattern matching statement is most useful for matching on algebraic types expressed via case classes. Scala also allows the definition of patterns independently of case classes, using unapply methods in extractor objects.
Pattern matching is a way of checking the given sequence of tokens for the presence of the specific pattern. It is the most widely used feature in Scala. It is a technique for checking a value against a pattern. It is similar to the switch statement of Java and C.
Pattern matching tests whether a given value (or sequence of values) has the shape defined by a pattern, and, if it does, binds the variables in the pattern to the corresponding components of the value (or sequence of values). The same variable name may not be bound more than once in a pattern.
When pattern matching Scala interprets all identifiers starting with lower case as placeholders and fills in values. To tell Scala to use to
as a constant value from the outer scope you need to surround it with backticks: `to`
. Alternatively, you could change the name of to
to To
as Rex Kerr suggested, but I prefer to keep my variables lowercase.
This should work:
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
}
}
It seems there are two confusions here. The first one is the one identified by Rex and Kim. You can read this section from Programming in Scala for more information. It boils down to:
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
You can also use a guard to constraint the match
x match { case Some(foo) if condition => }
The second confusion is that you want to "make a ChangeSet object with to from the method parameters". If I understand you correctly you are trying to construct an object using the case class syntax:
ChangeSet(field, from, to)
This does not work on that side of pattern matching. What happens on the case side of the pattern match can actually be seen as the reverse of the construction of ChangeSet. match { case ChangeSet(field, from, to) => }
sort of deconstructs your ChangeSet
object and assigns its parts to the field
, from
and to
vals. This is also true when it's composed like this: Some(ChangeSet(field, from, to))
, it first deconstructs Some
and then ChangeSet
. You can see that working on value definitions as it is leveraging the same deconstruction mechanism:
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
It seems what you want to do is to construct a new object that copies the value of ChangeSet
but replacing a single field. Case classes supports this with copy
, continuing with my REPL example:
scala> val cset2 = cset.copy(from = o2)
cset2: ChangeSet = ChangeSet(a,to,to)
With that in mind, here is another suggestion for 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
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With