Reputation: 77
In the first code snippet below, the case statement is defined inside a function and it works as expected.
def echoWhatYouGaveMe(x: Any): String = x match {
case (a, b) => s"got $a and $b"
case (a, b, c) => s"got $a, $b, and $c"
case _ => "Unknown"
}
object MatchTest extends App {
// trigger the tuple patterns
println(echoWhatYouGaveMe((1,2))) // two element tuple
println(echoWhatYouGaveMe((1,2,3))) // three element tuple
}
MatchTest.main(Array("dummy"))
got 1 and 2
got 1, 2, and 3
The case below is not within a function, but is otherwise very similar to above. It gives an error. I understand the error, but what I do not understand is why I am getting an error below and not an error above.
val myTuple = (1, 2, 3)
val toPrint = myTuple match {
case (a, b, c) => s"got $a, $b, and $c"
case (a, b) => s"got $a and $b"
case _ => s"Unknown data"
}
:14: error: constructor cannot be instantiated to expected type; found : (T1, T2) required: (Int, Int, Int) case (a, b) => s"got $a and $b"
Upvotes: 1
Views: 276
Reputation: 170733
When you write
val myTuple = (1, 2, 3)
the type of myTuple
is inferred to be (Int, Int, Int)
. So when you match
it, all patterns must be compatible with this type, i.e. there need to be values of this type which would match the pattern. Otherwise the pattern is useless and can as well be removed. case (a, b)
is such a useless pattern.
In snippet 1 the pattern isn't useless, because it is compatible with Any
.
Upvotes: 0
Reputation: 3638
The reason for such behavior of scala pattern matching lies in the type system. Scala has a very strong type system which allows high type safety and catches errors at compile time itself. If you declare a function having parameter instead of Any, it will also throw the same error.
For ex :-
def echoWhatYouGaveMe(x: (Int, Int)): String = x match {
case (a, b) => s"got $a and $b"
case (a, b, c) => s"got $a, $b, and $c"
case _ => "Unknown"
}
echoWhatYouGaveMe((1,2))
You get an error stating
Error:(4, 9) constructor cannot be instantiated to expected type;
found : (T1, T2, T3)
required: (Int, Int)
case (a, b, c) => s"got $a, $b, and $c"
^
If you modify your val myTuple and explicitly set its type to Any, it will allow you to perform pattern matching.
val myTuple: Any = (1, 2, 3)
val toPrint = myTuple match {
case (a, b, c) => s"got $a, $b, and $c"
case (a, b) => s"got $a and $b"
case _ => s"Unknown data"
}
You get an output like this
myTuple: Any = (1,2,3)
toPrint: String = got 1, 2, and 3
Upvotes: 9