pferrel
pferrel

Reputation: 5702

How to use a Scala Map[Any,Any]

I am very confused about why Scala doesn't allow things that it should be able to infer. If I want to store arbitrary types in a Map I imagine this should be possible but am blocked where there seems to be enough information to perform the operation.

scala> var m: Map[Any, Any] = Map()
m: Map[Any,Any] = Map()

scala> m = ("one" -> 1, 2 -> "two", 3 -> 3)
<console>:8: error: type mismatch;
 found   : ((String, Int), (Int, String), (Int, Int))
 required: Map[Any,Any]
       m = ("one" -> 1, 2 -> "two", 3 -> 3)
           ^

scala> m += ("one" -> 1)

scala> m += (2 -> "two")

scala> m += (3 -> 3)

scala> m
res25: Map[Any,Any] = Map(one -> 1, 2 -> two, 3 -> 3)

scala> m("one").getClass
res26: Class[_] = class java.lang.Integer

scala> m(3).getClass
res27: Class[_] = class java.lang.Integer

scala> val result = m("one")+m(3)
<console>:8: error: type mismatch;
 found   : Any
 required: String
       val result = m("one")+m(3)
                              ^

scala> val result: Int = m("one")+m(3)
<console>:8: error: type mismatch;
 found   : Any
 required: String
       val result: Int = m("one")+m(3)
                                   ^

scala> val mr1 = m("one")
mr1: Any = 1

scala> val mr1 = m("one") => Int
<console>:1: error: not a legal formal parameter.
Note: Tuples cannot be directly destructured in method or function parameters.
      Either create a single parameter accepting the Tuple1,
      or consider a pattern matching anonymous function: `{ case (param1, param1) => ... }
       val mr1 = m("one") => Int
                  ^

Ultimately I do know the type of the Key (String), and since the value's real types are known, I should be at least able to cast them, right? I also realize the code has to be type safe.

I'm clearly doing trial and mostly error here, can anyone offer guidance.

Upvotes: 0

Views: 1011

Answers (2)

dhg
dhg

Reputation: 52701

This is wrong:

m = ("one" -> 1, 2 -> "two", 3 -> 3)

You are trying to assign a Tuple3 to m, which you declared as a Map[Any,Any]. You meant:

m = Map("one" -> 1, 2 -> "two", 3 -> 3)

However, it's worth noting that a having things of type Any in your code is almost certainly a bad idea. Type-safety is great and is one of the major benefits of using Scala. You should take advantage of it.

Upvotes: 3

Lee
Lee

Reputation: 144206

In

m = ("one" -> 1, 2 -> "two", 3 -> 3)

you are trying to assign to m so the right-hand side must be compatible with Map[Any, Any]. However, ("one" -> 1, 2 -> "two", 3 -> 3) is a tuple which is not compatible, hence the error.

In

m += ("one" -> 1)

you are calling the + method of Map[Any, Any] with a Tuple2[Any, Any] argument. While ("one" -> 1) has type (String, Int) this is compatible with (Any, Any) so they can be added individually.

Note you can also do:

m += ("one" -> 1, 2 -> "two", 3 -> 3)

When you lookup elements in the map, the type of the return value is Any, so the types of m("one") and m(3) are both Any. Since Any has no + operator, m("one")+m(3) will not compile. If you know both values are Ints then you can cast them:

m("one").asInstanceOf[Int] +m(3).asInstanceOf[Int]

Upvotes: 3

Related Questions