Say you wish to use pattern matching when calling a method with varargs like so:
def foo(bar: Int*) = ???
val x = false
foo(x match {
case true => 1
case _ =>
})
Running the above code results in type mismatch error, since foo requires an argument of type Int but found Unit instead in the default case. Removing the default case, on the other hand, results in a warning that the match may not be exhaustive, and rightfully so.
My question is, how do I supply an empty default case for the match (which would result in calling foo() without any arguments)?
You could capture the match result in a sequence and represent the lack of arguments as an empty one. Then just splat the result into the parameter:
val x = true
foo((x match {
case true => Seq(1)
case _ => Seq.empty
}):_*)
One option would be to use an Option[Int] instead of an Int:
def foo(bar: Option[Int]*) = ???
val x = false
foo(x match {
case true => Some(1)
case _ => None
})
I think an if-else expression would be less verbose here:
foo(if (x) Some(1) else None)
I'd argue though that if you're matching over a single Boolean there's no point in passing varargs at all.
Related
I came across a code similar to this, and it was surprised that it even compiles:
scala> val halfSize: PartialFunction[String, Int] = _.length match {
case even if even % 2 == 0 => even / 2
}
halfSize: PartialFunction[String,Int] = <function1>
scala> List("x", "xx").collect(halfSize)
res1: List[Int] = List(1)
As far as I known, the valid syntax to define a PartialFunction is a case function:
val halfSize: PartialFunction[String, Int] = {
case s if s.length % 2 == 0 => s.length / 2
}
The first code seems more optimized since it calls length only once. But even in the SLS I was not able to find the explanation of the syntax. Is this an undocumented feature of scalac ?
The rules are given in https://www.scala-lang.org/files/archive/spec/2.12/06-expressions.html#anonymous-functions:
The eventual run-time value of an anonymous function is determined by the expected type:
...
PartialFunction[T, U], if the function literal is of the shape x => x match { … }
In this case the literal does have such a shape, as rogue-one's answer explains, so PartialFunction is allowed as the expected type.
(EDIT: actually, it doesn't, since it matches x.length instead of x. This looks like a minor bug, but one which should be fixed by changing the specification.)
A PartialFunction's value receives an additional isDefinedAt member, which is derived from the pattern match in the function literal, with each case's body being replaced by true, and an added default (if none was given) that evaluates to false.
So in this case it ends up with
def isDefinedAt(x: String) = x.length match {
case even if even % 2 == 0 => true
case _ => false
}
val halfSize: PartialFunction[String, Int] = _.length match {
case even if even % 2 == 0 => even / 2
}
The underscore (_) in the above function is just a short hand notation that refers to the single argument of the function. Thus the above snippet is just a short form of
val halfSize: PartialFunction[String, Int] = { (x: String) => x.length match {
case even if even % 2 == 0 => even / 2
}
}
If I have Scala tuple Option of the likes:
(Some(1), None)
(None, Some(1))
(None, None)
And I want always to extract always the "Some" value if it exists, and otherwise get the None. The only way with pattern matching?
There is this:
def oneOf[A](tup: (Option[A], Option[A])) = tup._1.orElse(tup._2)
That will return the first option that is defined, or None if neither is.
Edit:
Another way to phrase the same thing is
def oneOf[A](tup: (Option[A], Option[A])) =
tup match { case (first, second) => first.orElse(second) }
It's longer, but perhaps more readable.
This should work:
def f(t: (Option[Int], Option[Int])): Option[Int] = t match {
case (Some(n), _) => Some(n)
case (_, Some(n)) => Some(n)
case _ => None
}
I want always to extract always the Some value if it exists, and otherwise get the None
You can just use orElse
def orOption[T](p: (Option[T], Option[T])): Option[T] = {
val (o1, o2) = p
o1 orElse o2
}
However, this does decide what to do if there exists two Some values:
scala> orOption((Some(1), Some(2)))
res0: Option[Int] = Some(1)
You should probably use pattern matching and then decide what to do if there are two Some values, like throw an exception. Alternatively, consider using a better encoding for the result type than Option.
I have to find if an element is inside a list using scala, and I am only allowed to use recursion. Why is the following code not working, as the match statement seems to be correct to me. My IDE gives me an error on all three case statements and it says type, mistmatch, boolean required.
def isInN(x: Int, l: List[Int]): Boolean = (l,l.head) match {
case Nil,_ => false
case _,x => true
case _,_ => isInN (x,l.tail)
}
You're matching a tuple, so you need to use a proper tuple extractor. i.e. just add parenthesis:
def isInN(x: Int, l: List[Int]): Boolean = (l, l.head) match {
case (Nil, _) => false
case (_, x) => true
case (_, _) => isInN (x, l.tail)
}
This compiles, but won't quite work like you want it to. l.head will throw an exception if the list is empty. And x within the match will eagerly match anything, so the last case can never be reached. To match against an identifier, you need to surround it with backticks, otherwise it will just be a placeholder matcher.
To use a similar pattern match without calling l.head, you can pattern match on the List itself:
def isInN(x: Int, l: List[Int]): Boolean = l match {
case Nil => false
case `x` :: _ => true
case head :: tail => isInN (x, tail)
}
Though this is all trumped by contains in the standard collections library:
scala> List(1, 2, 3, 4).contains(2)
res5: Boolean = true
I want to handle my if condition based on the type of a variable which is predefined to be Any type and later it got updated to a type either String, Int, double, List or Map
if (type(x)==int){.....}
else if (type(x)==Map){....}
and so on
Is there a function to get the type of a variable or how can i get the type of a variable
to use it in if conditions.I know one of the way is to use
x.getClass.getSimpleName
but when the type of x is a Map
it prints Map1 or Map2 for different Maps which i am not sure what 1 and 2 denotes here
so i cant use it in the if condition since
if (x.getClass.getSimpleName==Map){....}
will be false as I dont know Map1 or Map2 will come
We call this pattern matching and it's one of the most awesome scala parts:
def foo(x: Any) = x match {
case m: Map[_,_] => println("I'm a map!")
case d: Double => println("I'm a double")
case i: Int => println("I'm an int")
case xs: List[_] => println("I'm a list")
}
Underscores denote any type, i don't care which one
Please point me to correct link if this has been answered before.
I have this code:
def getResult(a:Any):Any = a
def getAnswer[T](i:Int) = {
val result = getResult(i)
result match {
case t:T => Some(t)
case _ => None
}
}
This gives me a unchecked warning and everything matches to T. For instance, when I do getAnswer[Int](2), I get Some(2) (as expected). However, if I do getAnswer[String](2), I also get Some(2) which is not expected (I need None).
Is there any way to work around type erasure and somehow get getAnswer to work correctly (i.e., return Some(result) if and only if the result is of type T)?
Thanks in advance.
def getAnswer[T](i:Any)(implicit m:Manifest[T]) = i match {
case t:Int if m.erasure == classOf[Int] => Some(t)
case t:Double if m.erasure == classOf[Double] => Some(t)
//... other Primitives
case t if m.erasure.isInstance(t) => Some(t) //this matches AnyRefs
case _ => None
}
As Alexey wrote, you have some trouble with primitives. The technique used in the Scala sources in such cases involves always separate matches for every single primitive type, so I guess there is no way around.
This works with some limitations (T must be a class and not a primitive type; if T is generic, parameters are ignored).
def getAnswer[T](i:AnyRef)(implicit m:ClassManifest[T]) = {
val result = getResult(i)
if (result.getClass == m.erasure) Some(result.asInstanceOf[T]) else None
}
> getAnswer[java.lang.Integer](2.asInstanceOf[AnyRef])
res4: Option[java.lang.Integer] = Some(2)
getAnswer[String](2.asInstanceOf[AnyRef])
res1: Option[String] = None