Something like:
def cast[T](o: Any): Option[T] = o match {
case v: T => Some(v)
case _ => None
}
or:
def cast[T](c: Class[T], o: Any): Option[T] = o match {
case v: T => Some(v)
case _ => None
}
Is this a good idea? Is there a standard library equivalent?
Why do I get and how do I resolve the following Scala compiler warning:
Warning:(7, 13) abstract type pattern T is unchecked since it is eliminated by erasure
case v: T => Some(v)
Use class tag. Type information gets lost during runtime.So, you need provide type information which can be done using class tag.
import scala.reflect.ClassTag
def cast[T: ClassTag](o: Any): Option[T] = o match {
case v: T => Some(v)
case _ => None
}
Scala REPL
scala> cast[String]("hello")
res2: Option[String] = Some(hello)
scala> cast[Int]("scala")
res3: Option[Int] = None
Related
Given
a value of type Any
a TypeTag corresponding to the desired type
How can I cast the value
Unfortunately, the following snippet doesn't compile
val v: Any = 123
val tag = typeTag[Int]
val i = v.asInstanceOf[t.tpe]
Use this
import scala.reflect.ClassTag
def getTypedArg[T: ClassTag](any: Any): Option[T] = {
any match {
case t: T => Some(t)
case invalid =>
None
}
}
Usage
scala> getTypedArg[Int](5)
res1: Option[Int] = Some(5)
scala> getTypedArg[Int]("str")
res2: Option[Int] = None
Source: Retrieve class-name from ClassTag
EDIT-1
As asked by #Aki, it can be made to work with TypeTags too, with this hack
import reflect.runtime.universe._
import scala.reflect.ClassTag
def typeToClassTag[T: TypeTag]: ClassTag[T] = {
ClassTag[T]( typeTag[T].mirror.runtimeClass( typeTag[T].tpe ) )
}
def getTypedArg2[T: TypeTag](any: Any): Option[T] = {
implicit val c: ClassTag[T] = typeToClassTag[T]
any match {
case t: T => Some(t)
case invalid =>
None
}
}
Reference: How to get ClassTag form TypeTag, or both at same time?
You could write your own method that does the casting.
(note that this method will never throw ClassCastExceptions)
def cast[A](a: Any, tag: TypeTag[A]): A = a.asInstanceOf[A]
I would like to do something like this:
implicit class MyString(s: String) {
def getAs[T]: T = {
T match {
case q if q == classOf[Int] => s.toInt
case q if q == classOf[Boolean] => s.toBoolean
}
}
}
This doesn't compile, of course. How do I write this so it does?
Consider this approach:
object Parse {
def parse[T](f:String => Option[T]) = f
implicit val parseInt = parse(s => Try(s.toInt).toOption)
implicit val parseLong = parse(s => Try(s.toLong).toOption)
implicit val parseDouble = parse(s => Try(s.toDouble).toOption)
implicit val parseBoolean = parse(s => Try(s.toBoolean).toOption)
}
implicit class MyString(s:String) {
def getAs[T]()(implicit run: String => Option[T]): Option[T] = run(s)
}
Usage:
def main(args: Array[String]) {
import Parse._
"true".getAs[Boolean].foreach(println)
"12345".getAs[Int].foreach(println)
}
When use classOf for type match, there maybe will have some issues, example:
scala> classOf[List[Int]] == classOf[List[String]]
res17: Boolean = true
scala> typeOf[List[Int]] =:= typeOf[List[String]]
res18: Boolean = false
classOf only store the class information not with generics type
typeOf will store full type information
TypeTags and Manifests
class MyString(s: String) {
def getAs[T](implicit tag: TypeTag[T]): T = {
tag.tpe match {
case t if t =:= typeOf[Int] => s.toInt.asInstanceOf[T]
}
}
}
scala> new MyString("123")
res2: MyString = MyString#7fca02
scala> res6.getAs[Int]
res3: Int = 123
use TypeType tag to get type info, and call getAs with type information.
This is what I have come up with so far:
import reflect.runtime.universe.TypeTag
import scala.reflection.runtime.universe._
implicit class MyString(s: String) {
def getAs[T : TypeTag]: T = {
typeOf[T] match {
case t if t =:= typeOf[Int] => s.toInt.asInstanceOf[T]
case t if t =:= typeOf[Boolean] => s.toBoolean.asInstanceOf[T]
}
}
}
Running with this in REPL:
scala> "32".getAs[Int]
res25: Int = 32
scala> "32".getAs[Boolean]
java.lang.IllegalArgumentException: For input string: "32"
at scala.collection.immutable.StringLike$class.parseBoolean(StringLike.scala:290)
at scala.collection.immutable.StringLike$class.toBoolean(StringLike.scala:260)
at scala.collection.immutable.StringOps.toBoolean(StringOps.scala:30)
at MyString.getAs(<console>:33)
... 43 elided
scala> "false".getAs[Int]
java.lang.NumberFormatException: For input string: "false"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at scala.collection.immutable.StringLike$class.toInt(StringLike.scala:272)
at scala.collection.immutable.StringOps.toInt(StringOps.scala:30)
at MyString.getAs(<console>:32)
... 43 elided
scala> "false".getAs[Boolean]
res28: Boolean = false
scala> "false".getAs[String]
scala.MatchError: String (of class scala.reflect.internal.Types$AliasNoArgsTypeRef)
at MyString.getAs(<console>:31)
... 43 elided
Better, I think, would be to return an option[T], and catch any issues such as a type T that isn't catered for, or attempting a cast that will fail. I started mucking around with scala's Try (and its .toOption method), but hit some odd errors so haven't gotten any further with that.
EDIT: just using a simple try-catch, we can get:
implicit class MyString(s: String) {
def getAs[T : TypeTag]: Option[T] = try {
typeOf[T] match {
case t if t =:= typeOf[Int] => Some(s.toInt.asInstanceOf[T])
case t if t =:= typeOf[Boolean] => Some(s.toBoolean.asInstanceOf[T])
}
} catch {
case ex: Exception => None
}
}
Resulting in:
scala> "false".getAs[String]
res30: Option[String] = None
scala> "32".getAs[Boolean]
res31: Option[Boolean] = None
scala> "32".getAs[Int]
res32: Option[Int] = Some(32)
scala> "true".getAs[Boolean]
res33: Option[Boolean] = Some(true)
scala> "true".getAs[Int]
res34: Option[Int] = None
Based on the answers given by #chengpohi and #Shadowlands, this is what I came up with.
object ImplicitsStartingWithS {
implicit class MyString(s: String) {
val str = s.trim
import reflect.runtime.universe.TypeTag
import scala.reflect.runtime.universe._
def getAs[T](implicit tag: TypeTag[T]): Option[T] = {
val value = tag.tpe match {
case t if t =:= typeOf[Int] => str.toIntStr.map(_.toInt)
case t if t =:= typeOf[Long] => str.toIntStr.map(_.toLong)
case t if t =:= typeOf[Float] => str.toNumericStr.map(_.toFloat)
case t if t =:= typeOf[Double] => str.toNumericStr.map(_.toDouble)
case _ => None
}
value.asInstanceOf[Option[T]]
}
def toDecimalStr = "^-*\\d+\\.\\d+$".r.findFirstIn(s)
def toIntStr = "^-*\\d+$".r.findFirstIn(s)
def toNumericStr = {
s.toDecimalStr match {
case Some(decimalStr) => Some(decimalStr)
case None => s.toIntStr
}
}
}
}
This avoids exception handling for faster response.
Given the following method:
scala> def f: List[Any] => Any = xs => 1234 // this output does not matter
f: List[Any] => Any
Is it possible to pattern match on List[Any] => Any? I don't see an unapply method on Function1, so I believe the answer is no.
Here's what I'm trying to do:
Example:
def foo(x: Any) = x match {
case ... // to handle the case of List[Any] => Any]?
case ...
}
Perhaps I can figure out the arity of x: Any to differentiate between List[Any] => Any versus everything else (_)?
EDIT:
I hope that I do not have to rely on f.toString == <function1>.
No, you can't match exactly on List[Any] => Any due to type erasure, but you can match on Function1 itself:
def foo(x: Any): String = x match {
case _: Function1[_, _] => "some function1"
case _ => "other"
}
Any other matching, like case _: (List[Any] => Any) => "function from list to any" will act the same as case _: Function1[_, _] => "some function":
scala> def foo(x: Any): String = x match {
| case _: (List[Any] => Any) => "function from list to any"
| case _ => "other"
| }
<console>:8: warning: non-variable type argument List[Any] in type pattern List[Any] => Any is unchecked since it is eliminated by erasure
case _: (List[Any] => Any) => "function from list to any"
^
foo: (x: Any)String
scala> def aaa(l: Any): Any = null //it's `Any => Any` - not `List[Any] => Any`!!
aaa: (l: Any)Any
scala> foo(aaa _)
res11: String = function from list to any
scala> foo(1)
res12: String = other
You can match purely on type, even without an unapply method:
def foo(x: Any): String = x match {
case _: (Any => Any) => "some function1"
case _ => "other"
}
And then you can check:
foo(f) //"some function1"
foo(1) //"other"
See the following code:
def createOption[T: TypeTag](referentialData: Any) : Option[T] = {
Option(referentialData) match {
case Some(camelMessage: CamelMessage) => {
Option(camelMessage.body) match {
case Some(option: T) => Some(option)
case _ => None
}
}
case _ => None
}
}
Basically I am looking to return an Option[T] if camelMessage.body is non-null and of type T.
The uses of Option(referentialData) is effectively referentialData != null
Likewise for Option(camelMessage.body)
How do I use the TypeTag to determine if camelMessage.body is of type T.
(I know this can be re-written to not use TypeTags and Options but I want to learn how to use TypeTags so please no suggestions to re-write, thanks!)
Edit
I tried a new approach as could not find a solution for the above, but could not get this one to work either:
def createOption[T](referentialData: Any) : Option[T] = {
Option(referentialData) match {
case Some(option) => Try(option.asInstanceOf[T]).toOption
case _ => None
}
}
When I invoke this using createOption[Long]("test") I was presuming to get a None back, but instead I got a Some(String)
Where am I going wrong here?
This is a duplicate of this one.
But you want to try it with ClassTag to show the limitation:
scala> def f[A: ClassTag](x: Any): Option[A] = x match {
| case y: A => println("OK"); Some(y) ; case _ => println("Nope"); None }
f: [A](x: Any)(implicit evidence$1: scala.reflect.ClassTag[A])Option[A]
scala> f[String]("foo")
OK
res0: Option[String] = Some(foo)
scala> f[Long](2L)
Nope
res1: Option[Long] = None
scala> f[java.lang.Long](new java.lang.Long(2L))
OK
res2: Option[Long] = Some(2)
scala> def f[A: TypeTag](x: Any): Option[A] = Option(x) match {
| case Some(y: A) => println("OK"); Some(y) ; case _ => println("Nope"); None }
<console>:51: warning: abstract type pattern A is unchecked since it is eliminated by erasure
case Some(y: A) => println("OK"); Some(y) ; case _ => println("Nope"); None }
^
f: [A](x: Any)(implicit evidence$1: reflect.runtime.universe.TypeTag[A])Option[A]
Given a hypothetical mutable linked list (let's assume this is a given structure -- so no suggestions about changing it, please):
trait CList[T]
trait CNil [T] extends CList[T]
trait CCons[T] extends CList[T] {
def head: T
def tail: CList[T]
}
And given Scala's type erasure, how can I iterate through it without casting:
#annotation.tailrec def lastValue[T](l: CList[T]): Option[T] = l match {
case _: CNil [_] => None
case c: CCons[_] => lastValue(c.asInstanceOf[CCons[T]]) // ouch!
}
CList is invariant in T so there should be way to accomplish this?
You can try defining extractors:
object CNil {
def unapply[T](clist: CList[T]): Boolean = clist.isInstanceOf[CNil[_]]
}
object CCons {
def unapply[T](clist: CList[T]): Option[(T, CList[T])] = clist match {
case _: CNil[_] => None
case c: CCons[_] => Some(c.head, c.tail)
}
}
#annotation.tailrec def lastValue[T](l: CList[T]): Option[T] = l match {
case CNil() => None
case CCons(head, tail) => lastValue(tail)
}
You may have to give them another name if you can't put them in the same files as where the original traits are defined.
On another point, the implementation of your lastValue function probably doesn't do what you expect… How about this one instead?
def lastValue[T](clist: CList[T]): Option[T] = {
#annotation.tailrec
def lastValue0(prevValue: Option[T], clist: CList[T]): Option[T] =
clist match {
case CNil() => prevValue
case CCons(head, tail) => lastValue0(Some(head), tail)
}
lastValue0(None, clist)
}