Suppose I need to convert a String to Int in Scala. If the string is not a number I would like to return None rather than throw an exception.
I found the following solution
def toMaybeInt(s:String) = {
import scala.util.control.Exception._
catching(classOf[NumberFormatException]) opt s.toInt
}
Does it make sense ? Would you change/improve it ?
I'd use scala.util.Try which returns Success or Failure for a computation that may throw an exception.
scala> val zero = "0"
zero: String = 0
scala> val foo = "foo"
foo: String = foo
scala> scala.util.Try(zero.toInt)
res5: scala.util.Try[Int] = Success(0)
scala> scala.util.Try(foo.toInt)
res6: scala.util.Try[Int] = Failure(java.lang.NumberFormatException: For input string: "foo")
So, toMaybeInt(s: String) becomes:
def toMaybeInt(s:String) = {
scala.util.Try(s.toInt)
}
For getting an option in any case, regardless of possible exceptions due to number malformation,
import scala.util.Try
def toOptInt(s:String) = Try(s.toInt) toOption
Then
scala> toOptInt("123")
res2: Option[Int] = Some(123)
scala> toOptInt("1a23")
res3: Option[Int] = None
Further, consider
implicit class convertToOptInt(val s: String) extends AnyVal {
def toOptInt() = Try(s.toInt) toOption
}
Hence
scala> "123".toOptInt
res5: Option[Int] = Some(123)
scala> "1a23".toOptInt
res6: Option[Int] = None
Related
Given a hex String, how can I programmatically create a Unicode String?
Example:
def f(x: String): String = s"\u$s"
fails to compile:
scala> def f(x: String): String = s"\u$s"
<console>:1: error: error in unicode escape
def f(x: String): String = s"\u$s"
^
I tried the following, but it failed:
scala> def f(x: String): String = "\\u" + x
f: (x: String)String
scala> f("0021")
res19: String = \u0021
scala> "\u0021"
res20: String = !
scala> res19 == res20
res21: Boolean = false
I don't know whether there's a way to call into the exact code the compiler is using, but doing it yourself seems simple enough.
Split the string into groups of 4 and use Integer.parseInt to get a code point, then convert it to a character.
scala> "27640021".grouped(4).map(Integer.parseInt(_, 16).toChar).mkString
res1: String = ❤!
When in doubt defer to the Java libs:
scala> def hexStrToChar(hex: String): Char = Integer.parseInt(hex, 16).toChar
hexStrToChar: (hex: String)Char
scala> hexStrToChar("0021")
res1: Char = !
I don't know why the following code can not compile, this is the error message:
Error:(29, 7) no type parameters for method flatMap: (f: String => Option[B])Option[B] exist so that it can be applied to arguments (String => Some[Class[?0]] forSome { type ?0 <: org.apache.hadoop.io.compress.CompressionCodec })
--- because ---
argument expression's type is not compatible with formal parameter type;
found : String => Some[Class[?0]] forSome { type ?0 <: org.apache.hadoop.io.compress.CompressionCodec }
required: String => Option[?B]
a.flatMap(codecClassName => {
^
and code
def f(a: Option[String]): Unit = {
a.flatMap(codecClassName => {
val codecFactory = new CompressionCodecFactory(new Configuration())
val codecClass = codecFactory.getCodecClassByName(codecClassName)
if (codecClass == null) {
throw new RuntimeException("Unknown or not supported codec:" + codecClassName)
}
Some(codecClass)
})
}
This seems to be related to the fact that getClass and classOf are not returning the exact same thing. See Scala equivalent of Java java.lang.Class<T> Object for more details.
Looking around for a workaround I came across Scala Getting class type from string representation.
So how about:
val codecClass = Manifest.classType(codecFactory.getCodecClassByName(codecClassName))
This should work. flatMap involves both map and flatten, so it may need more type annotations in some cases. The overall code works after annotation of the function parameter, i.e. (codecClassName: String).
Note the other change -- that flatMap with an inner function returning an Option type is the same as a map if that function returns what's inside the Option (i.e. flattens the option) (see below).
import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.io.compress.{CompressionCodec, CompressionCodecFactory}
...
def f(a: Option[String]): Option[Class[_ <: CompressionCodec]] = {
a.map((codecClassName: String) => {
val codecFactory = new CompressionCodecFactory(new Configuration())
val codecClass = codecFactory.getCodecClassByName(codecClassName)
if (codecClass == null) {
throw new RuntimeException("Unknown or not supported codec:" + codecClassName)
}
codecClass
})
}
To show the relationship between flatMap and map as described above:
scala> val opt: Option[Int] = Some(1)
opt: Option[Int] = Some(1)
scala> opt.map((i: Int) => i + 1)
res0: Option[Int] = Some(2)
scala> val opt2: Option[Int] = None
opt2: Option[Int] = None
scala> opt.flatMap((i: Int) => Some(i + 1))
res1: Option[Int] = Some(2)
scala> opt2.map((i: Int) => i + 1)
res3: Option[Int] = None
scala> opt2.flatMap((i: Int) => Some(i + 1))
res2: Option[Int] = None
I'm having this implicit def to convert an Option[Int] to an Option[String]
implicit def optIntOptString(n: Option[Int]): Option[String] = Some(n.get.toString)
while this one works:
val optIntVal: Option[Int] = Some(3)
val converted: Option[String] = optIntVal // the 'optIntVal' which is of type Option[Int] gets converted implicitly to Option[String] due to the implicit def 'optIntOptString'
this doesn't:
val failConv: Option[String] = Some(3)
found : Int(3)
required: String
val failConv: Option[String] = Some(3)
I'm trying to do a conversion without using an intermediary val
My intention is to use the implicit conversion within a map/flatmap function, something like:
val someList: List[Int] = List(1, 2, 3)
someList.map((num:Int) => {
val z:Option[String] = Some(num)
z
})
But even with an intermediary val that holds the source type i get an error, seems like the implicit conversion isn't working within the map method:
found : Int
required: String
someList.map((num:Int) => { val z:Option[String] = Some(num); z })
I'm trying to test whether a method's return type exactly matches a supplied type.
Somehow, I've found two String Types that are not equal.
class VarAndValue {
#BeanProperty
val value = "";
}
class ScalaReflectionTest {
#Test
def myTest(): Unit = {
val type1 = universe.typeOf[String]
// Get return value of VarAndValue.getValue
val type2 = universe.typeOf[VarAndValue].
declarations.
filter { m => m.name.decoded == "getValue" && m.isMethod }.
head.
asInstanceOf[universe.MethodSymbol].
returnType
println(type1) // String
println(type2) // String
println(type1.getClass())
println(type2.getClass()) // !=type1.getClass() !!
println(type1==type2) // False
}
}
yields...
String
String
class scala.reflect.internal.Types$TypeRef$$anon$3
class scala.reflect.internal.Types$TypeRef$$anon$6
false
How can I filter methods of a class by their return type? (It seems very difficult if I can test for equality of the return types).
Scala 2.10
UPDATE:
I can't drop into the Java reflection universe because this erased type information for generics like List[Int] (which become List[Object] is java-land where they're really List[java.lang.Integer]). I need my matched to pay attention to the generic parameter information that the scala type universe preserves.
Use =:= to compare types.
scala> import beans._
import beans._
scala> :pa
// Entering paste mode (ctrl-D to finish)
class VarAndValue {
#BeanProperty
val value = "";
}
// Exiting paste mode, now interpreting.
defined class VarAndValue
scala> import reflect.runtime._, universe._
import reflect.runtime._
import universe._
scala> val str = typeOf[String]
str: reflect.runtime.universe.Type = String
scala> val ms = typeOf[VarAndValue].declarations filter (m => m.isMethod && m.name.decoded == "getValue")
warning: there were two deprecation warnings; re-run with -deprecation for details
ms: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(method getValue)
scala> val mm = ms.toList
mm: List[reflect.runtime.universe.Symbol] = List(method getValue)
scala> val m = mm.head.asInstanceOf[MethodSymbol]
m: reflect.runtime.universe.MethodSymbol = method getValue
scala> val t = m.returnType
t: reflect.runtime.universe.Type = java.lang.String
scala> println(t)
java.lang.String
scala> println(str)
String
scala> str == t
res2: Boolean = false
scala> str match { case `t` => }
scala.MatchError: String (of class scala.reflect.internal.Types$AliasNoArgsTypeRef)
... 33 elided
scala> str =:= t
res4: Boolean = true
scala> str match { case TypeRef(a,b,c) => (a,b,c) }
res5: (reflect.runtime.universe.Type, reflect.runtime.universe.Symbol, List[reflect.runtime.universe.Type]) = (scala.Predef.type,type String,List())
scala> t match { case TypeRef(a,b,c) => (a,b,c) }
res6: (reflect.runtime.universe.Type, reflect.runtime.universe.Symbol, List[reflect.runtime.universe.Type]) = (java.lang.type,class String,List())
Depending on what you're going for, consider that conforming types can have differing representations:
scala> typeOf[List[Int]]
res11: reflect.runtime.universe.Type = scala.List[Int]
scala> type X = List[Int]
defined type alias X
scala> typeOf[X].dealias
res12: reflect.runtime.universe.Type = List[scala.Int]
scala> res11 =:= res12
res13: Boolean = true
scala> res11 == res12
res14: Boolean = false
scala> typeOf[X] <:< res11
res15: Boolean = true
scala> typeOf[X] =:= res11
res16: Boolean = true
Turns out this is the way to compare types ...
type1 match {
case type2 => true
case _ => false
}
which gives a different answer than type1==type.
Scala is a strange beast.
Is it possible to get the type of a type field after creating an object ?
I would like to do something like this:
scala> class A { type T = String }
defined class A
scala> val a = new A
a: A = A#591171
scala> a.T
<console>:13: error: value T is not a member of A
a.T
^
The last
What do you want to do with the type? You can use a type projection in various ways with the class's type (without an instance):
scala> class A { type T = String }
defined class A
scala> val x: A#T = "test"
x: java.lang.String = test
scala> def f(b: A#T) = b
f: (a: java.lang.String)java.lang.String
Or if you enable -Ydependent-method-types, you can get the type member from the instance:
scala> val a = new A
a: A = A#6a3de2df
scala> val x: a.T = "test"
x: a.T = test
scala> def f(b: a.T) = b
f: (b: a.T)a.T
Scala's reflection API prior to 2.10 doesn't really model types in any clean way, so if you want to "get the type" in some other sense, you're probably out of luck.
One way is with reflection (since 2.10M4):
// with static types
scala> class A { type T = String }
defined class A
scala> import reflect.runtime.{universe => u}
import reflect.runtime.{universe=>u}
scala> val t = u.typeOf[A]
t: reflect.runtime.universe.Type = A
scala> val types = t.declarations.filter(_.isType)
types: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(type T)
scala> types.toList.head.typeSignature
res9: reflect.runtime.universe.Type = String
// with instances
scala> val a = new A
a: A = A#68d7c870
scala> import reflect.runtime.{currentMirror => m}
import reflect.runtime.{currentMirror=>m}
scala> m.reflect(a).symbol.asType // same type as t
res20: reflect.runtime.universe.Type = A