In the following code:
def test(list: List[Any]): Unit = {
list.foreach {
v =>
v match {
case r: AnyRef => println(r + ": " + r.getClass.getName)
case d: Double => println(d + ": Double")
case f: Float=> println(f + ": Float")
case b: Byte => println(b + ": Byte")
case c: Char => println(c + ": Char")
case s: Short => println(s + ": Short")
case i: Int => println(i + ": Int")
case l: Long=> println(l + ": Long")
case b: Boolean => println(b + ": Boolean")
case _ => throw new IllegalArgumentException("Unknown type: " + v)
}
}
}
test(List(0L, 1.asInstanceOf[Int], 2.asInstanceOf[Short]))
here is the output (Scala 2.8.1):
0: java.lang.Long
1: java.lang.Long
2: java.lang.Long
Why are the numbers being promoted to java.lang.Long? How can I do this so that they either keep their AnyVal
types or get "boxed" to the equivalent AnyRef
type?
Following are the point of difference between lists and array in Scala: Lists are immutable whereas arrays are mutable in Scala. Lists represents a linked list whereas arrays are flat.
Specific to Scala, a list is a collection which contains immutable data, which means that once the list is created, then it can not be altered. In Scala, the list represents a linked list. In a Scala list, each element need not be of the same data type.
Lists are immutable --- the elements of a list cannot be changed, Lists are recursive (as you will see in the next subsection), Lists are homogeneous: A list is intended to be composed of elements that all have the same type.
This is the first method we use to append Scala List using the operator “:+”. The syntax we use in this method is; first to declare the list name and then use the ':+' method rather than the new element that will be appended in the list. The syntax looks like “List name:+ new elements”.
I think the answer is in Section 3.5.3 of the language reference:
Because of this, Scala infers that the common type between Short, Int and Long is Long and then converts the non-Long objects to Longs:
scala> List(0L, 0, 0: Short)
res1: List[Long] = List(0, 0, 0)
If you want to use the whole chain of weak conformance, try:
scala> List(0: Byte, 1: Short, 'c', 3, 4L, 5.0f, 6.0)
res2: List[Double] = List(0.0, 1.0, 99.0, 3.0, 4.0, 5.0, 6.0)
And, of course to say that you want a List[Any]
, just add [Any]
to your call to List
:
scala> List[Any](0: Byte, 1: Short, 'c', 3, 4L, 5.0f, 6.0)
res11: List[Any] = List(0, 1, c, 3, 4, 5.0, 6.0)
Type inference works by starting with the most restrictive type (e.g. Nothing
) and widening until one type can contain everything. For numeric values, this means widening from Int
to Long
. But now, since the call is effectively to List[Long](ls: Long*)
all the numeric values are promoted in advance.
So, for instance, all of these give the same list:
List(1, 2: Byte, 3: Long)
List(1L, 2, 3: Short)
List(1: Byte, 2: Long, 3: Byte)
namely a List[Long](1L, 2L, 3L)
. Now, if you don't like this behavior, specify the type of the list as AnyVal
or Any
:
List[Any](1, 2: Byte, 3: Long)
List.head.asInstanceOf[AnyRef].getClass // java.lang.Integer
Edit: P.S. if you are specifying a constant of a certain type, you should just state the type (e.g. (2: Short)
) instead of casting it to that type (e.g. 2.asInstanceOf[Short]
).
List[Any](0L, 1.asInstanceOf[Int], 2.asInstanceOf[Short])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With