I have enum like this.
object SortCountryField extends Enumeration {
type SortCountryField = Value
val countryName = Value("country_name")
val countryStatus = Value("country_status")
}
I'm using this SortCountryField enum in match-case.
Here I need to convert toString every time.
To make it convenient I'm trying to implicit converter to extract String from SortCountryField.{Value}
However, I end up having a compiler error when I use the implicit function in following match case.
'myString' match{
case SortCountryField.countryName.toString => //Some operations
case SortCountryField.countryStatus.toString => //another operation
}
Error Log:-
found : mypackage.ConstantUtils.SortCountryField.Value
[error] required: String
[error] case SortCountryField.countryStatus => //my-operations
I think you'd be better off using the enum in your match like:
SortCountryField withName <your_string> match {
case SortCountryField.countryName => //Some operations
case SortCountryField.countryStatus => //another operation
}
If your string sometimes doesn't match any field then you can easily wrap this in a Try like in the following code:
Try(SortCountryField withName <your_string>) match {
case Success(SortCountryField.countryName) => //Some operations
case Success(SortCountryField.countryStatus) => //another operation
case _ => //another operation
}
You can also do:
'myString' match{
case x if x == SortCountryField.countryName.toString => //Some operations
case x if x == SortCountryField.countryStatus.toString => //another operation
}
How does your implicit converter looks like?
My guess is that you have converter SortCountryField => String, but you need SortCountryField.Value => String converter.
Add below function in your enum:
implicit def toString(value: Value): String = value.toString
Use below in matching:
val countryStaus:String = SortCountryField.countryStatus
'myString' match {
case `countryStatus` => //Some operations
case _ => // Another operation
}
Related
I am writing an implicit reads returning JsResult[Seq[T]] based on a condition:
some_condition match{
case Some(value) => // JsResult[Seq[T]]
case _ => // returning an empty JsResult here of similar type?
}
What would be the way for return such JsResult?
You will need to use the method validate, which returns JsResult. There are 2 case classes that inherits JsResult:
JsSuccess
JsError
Therefore you can consider the following example:
case class T()
implicit val reads = Json.reads[T]
val jsValue: JsValue = ...
jsValue.validate[Seq[T]] match {
case JsSuccess(t, path) =>
println(t)
case JsError(errors) =>
println(errors)
}
I'm trying to match an enum value converted to a string held in a collection. Here's the code:
object Foo extends Enumeration {
val ONE = Value("ONE")
val TWO = Value("TWO")
}
def check(seq: Seq[String]): Unit = seq match {
case Seq(Foo.ONE.toString) => println("match")
case _ => println("no match")
}
This results in a compilation error:
error: stable identifier required, but Foo.ONE.toString found.
case Seq(Foo.ONE.toString) => println("match")
What is the proper way to use my Foo enumerated values as elements of my pattern matching case statements?
Map it back to the enum first:
import scala.util.Try
val enumSeq = seq map (x => Try(Foo.withName(x)))
Then you can either filter out the Failures or match on Seq(Success(ONE)), Seq(Success(ONE)), ..., Seq(Failure), etc.
def check(seq: Seq[String]): Unit = seq match {
case Seq(s # _) if s == Foo.ONE.toString => println("match")
case _ => println("no match")
}
I like the response from #cchantep, which was to avoid calling .toString inside the pattern match and implement the check method like so:
def check(seq: Seq[Foo.Value]): Unit = seq match {
case Seq(Foo.ONE) => println("match")
case _ => println("no match")
}
I have a type whose shape is like this:
val myType: Future[Either[MyError, TypeA]] = // some value
I know that I could pattern match on this and get to the Right or Left type, but the problem is that I would have to nest my pattern matching logic. I'm looking for much more elegant way of handling this? Any suggestions?
If you encode your MyError as an exception, you don't need the Either anymore and can simply patternMatch against the completion, or use a recoverWith to map it to another type:
myType.onComplete {
case Success(t) =>
case Failure(e) =>
}
To map your existing Either types you could do something like this:
case class MyException(e: MyError) extends Exception
def eitherToException[A](f: Future[Either[MyError,A]]): Future[A] = {
f.flatMap {
case Left(e) => Future.failed(MyException(e))
case Right(x) => Future.successful(x)
}
}
val myType2 = eitherToException(myType)
Alternatively, if MyError and TypeA are under your control, you could create a common super type and pattern match against that:
sealed trait MyResult
final case class MyError() extends MyResult
final case class TypeA() extends MyResult
myType.map {
case MyError() => ...
case TypeA() => ...
}
You can create custom extractor objects:
object FullSuccess {
def unapply[T](x: Try[Either[MyError, T]]) = x match {
case Success(Right(x)) => Some(x)
case _ => None
}
}
object PartSuccess {
def unapply[T](x: Try[Either[MyError, T]]) = x match {
case Success(Left(err)) => Some(err)
case _ => None
}
}
And
val myType: Future[Either[MyError, TypeA]] = // some value
myType.onComplete {
case FullSuccess(x) => ... // equivalent to case Success(Right(x))
case PartSuccess(x) => ... // equivalent to case Success(Left(x))
case Failure(e) => ...
}
I have an enum for keywords and operators (and some other too), e.g. (all are similar):
object Keywords extends Enumeration {
val AND, ARRAY, BEGIN, ...= Value
case class Keyword(keyword: Value) extends Token[Value] {
def this(keyword: String) = this(Keywords.fromString(keyword))
def value = keyword
}
implicit def valueToKeyword(keyword: Value) = new Keyword(keyword)
}
this implicit conversion allows me to pass enum values where Tokens are expected e.g.
def testFunction[T](t: Token[T]) = ...
testFunction(Keywords.ARRAY) // gets converted
testFunction(Operators.PLUS) // gets converted too
it also seems that the same implicit conversion is not applied during matching i.e.
val token = new Keyword("ARRAY")
token match {
case Keywords.ARRAY => ... // not selected but SHOULD be
case Operators.PLUS => ... // completely different Enum
...
}
Why? How to overcome this?
This doesn't work because:
token match {
case Keywords.ARRAY => println("Array")
case _ => println("Something else")
}
is essentially a PartialFunction with the following type signature: PartialFunction[Keywords.Value, Unit]. Which means an implicit won't be applied, because it's either isDefinedAt or it isn't for that input.
If it isn't defined than case _ => ... will catch everything in my example code. If it's not defined at all and nothing will match it then you will get a MatchError thrown.
In your case token of type Token[Value] isn't defined in the Partial Function that the match will compile to, because only types of Keywords.Value are defined.
Three solutions
If you really want implicits then you could explicitly ask for an implicit (yes, that sentence is funny :))
implicitly[Keywords.Value](token) match {
case Keywords.ARRAY => println("Array")
case _ => println("Something else")
}
Or you can explicitly state the type of token, to invoke the implicit magic:
val token: Keywords.Value = new Keyword("ARRAY")
token match {
case Keywords.ARRAY => println("Array")
case _ => println("Something else")
}
Or the simplest solution if you can live without implicits:
token.value match {
case Keywords.ARRAY => println("Array")
case _ => println("Something else")
}
I know it's not the answer you're looking for, but I hope that you understood what match {...} really means and what Partial Functions are.
How would you implement class that parses some input via regex and transforms founded string to some other type? My approach is:
class ARegex[T](regex:Regex, reform:Option[String => T]){
def findFirst(input:String):Option[T] = {
(regex.findFirstIn(input), reform) match{
case (None, _) => None
case (Some(s), None) => Some(s) // this won't compile because of type mismatch
case (Some(s), Some(fun)) => Some(fun(s))
}
}
}
class BRegex[T](regex:Regex, reform:Option[String => T]) {
def findFirst(input:String) = { //returns Option[Any] - erasure
(regex.findFirstIn(input), reform) match{
case (None, _) => None
case (Some(s), None) => Some(s)
case (Some(s), Some(fun)) => Some(fun(s))
}
}
}
We can solve this problem by eliminating the Option part of the reform's type, and using a different mechanism to indicate that we don't want to change the match in any way. This mechanism is to use identity as a default parameter or pass identity when you don't want the type to change.
class ARegex[T](regex:Regex, reform:String => T = identity[String](_)){
def findFirst(input:String):Option[T] = {
regex.findFirstIn(input) match{
case None => None
case Some(s) => Some(reform(s))
}
}
}
new ARegex("something".r).findFirst("something else") //returns Option[String]
new ARegex("3".r, {x=>x.toInt}).findFirst("number 3") //returns Option[Int]
Well, the problem is the type mismatch, because you are returning either a String or a T, which, of course, are unified at Any. You can't say you are going to return Option[T] and then return Option[String].
Other than that, a simplified version of that code is this:
class ARegex[T](regex: Regex, reform: Option[String => T]) {
def findFirst(input: String): Option[Any] =
regex findFirstIn input map { s => reform map (_(s)) getOrElse s }
}
You could return an Option[Either[String, T]], though. The code would look like this:
class ARegex[T](regex: Regex, reform: Option[String => T]) {
def findFirst(input: String): Option[Either[String, T]] =
regex findFirstIn input map { s => reform map (_(s)) toRight s }
}
Why is reform Option[String => T] instead of just String => T? If you don't pass in a mechanism for creating an instance of your desired type, there's no mechanism for the runtime system to actually create the appropriate object. If you really need to pass in an Option[String => T] then your second case should simply return None.
Also, flatMap is your friend, and will give you the correct behavior (i.e. if reform is None, the method returns None.
class RegexExtractor[T](regex: Regex, reform: Option[String => T]) {
def findFirst(input: String): Option[T] = reform.flatMap(f => regex.findFirstIn(input).map(f))
}