Scala:可以为不同的键使用不同数据类型的HashMap吗?

Scala:可以为不同的键使用不同数据类型的HashMap吗?,scala,hashmap,wildcard,listbuffer,Scala,Hashmap,Wildcard,Listbuffer,我对使用Scala编程完全陌生,我有以下问题: 我需要一个HashMap,它可以包含许多数据类型(Int、String等)。在C++中我会使用Boost的MultMAP。我听说在Scala中有一种多重映射特性可用。基本上我想说的是: val map = HashMap[String, ListBuffer[_]] ListBuffer元素的具体数据类型将在运行时确定。当我在控制台中测试此实现时,以下工作正常: scala> val a = new HashMap[String, List

我对使用Scala编程完全陌生,我有以下问题:

我需要一个HashMap,它可以包含许多数据类型(Int、String等)。在C++中我会使用Boost的MultMAP。我听说在Scala中有一种多重映射特性可用。基本上我想说的是:

val map = HashMap[String, ListBuffer[_]]
ListBuffer元素的具体数据类型将在运行时确定。当我在控制台中测试此实现时,以下工作正常:

scala> val a = new HashMap[String, ListBuffer[_]]()
a: scala.collection.mutable.HashMap[String,scala.collection.mutable.ListBuffer[_]] = Map()

scala> val b = new ListBuffer[String]()
b: scala.collection.mutable.ListBuffer[String] = ListBuffer()

scala> val c = new ListBuffer[Int]()
c: scala.collection.mutable.ListBuffer[Int] = ListBuffer()

scala> b += "String"
res0: b.type = ListBuffer(String)

scala> c += 1
res1: c.type = ListBuffer(1)

scala> a += "String Buffer" -> b
res2: a.type = Map((String Buffer,ListBuffer(String)))

scala> a += "This is an Int Buffer" -> c
res3: a.type = Map((String Buffer,ListBuffer(String)), (This is an Int Buffer,ListBuffer(1)))
所以基本上它是有效的。我的第一个问题是,是否有可能在Scala中实现相同的行为,而不使用ListBuffer作为间接层

例如,获取具有以下内容的映射:映射((字符串,1),(字符串,“字符串值”),…)

当我现在尝试使用上面的ListBuffer实现时,出现以下类型不匹配错误:

found   : _$1 where type _$1
required: _$3 where type _$3
我基本上是在做以下工作:

val map = HashMap[String, ListBuffer[_]]
我使用迭代器对贴图的键进行迭代:

var valueIds = new ListBuffer[Int]()
val iterator = map.keys
iterator.foreach(key => { valueIds += setValue((map.apply(key)).last) }
setValue返回Int,是一个必须处理ListBuffers最后一个元素的方法

有人知道如何修复上述类型不匹配吗

谢谢你的帮助

关于Scala有一个类

我认为在查看代码以了解您需要什么时,这是有道理的。

Scala有一个类


我认为这在查看代码时很有意义。

每个键需要存储多个值吗?如果是这样,无论如何都需要使用
ListBuffer
或其他集合。(Scala的
MultiMap
s存储集,因此如果需要保存副本,它们将无法工作。)

如果不需要每个键存储多个值,则只需要
Any
类型:

scala> val map = collection.mutable.HashMap[String,Any]()
map: scala.collection.mutable.HashMap[String,Any] = Map()

scala> map += "One" -> 1
res1: map.type = Map((One,1))

scala> map += "Two" -> "ii"
res2: map.type = Map((Two,ii), (One,1))

scala> map += "Three" -> None
res3: map.type = Map((Three,None), (Two,ii), (One,1))
您现在可能需要执行模式匹配或使用collect对值执行任何有用的操作:

scala> map.values.foreach(_ match { case i: Int => println("We stored the number "+i) })
We stored the number 1

scala> map.values.collect{ case i: Int => i }
res4: Iterable[Int] = List(1)

是否需要每个键存储多个值?如果是这样,无论如何都需要使用
ListBuffer
或其他集合。(Scala的
MultiMap
s存储集,因此如果需要保存副本,它们将无法工作。)

如果不需要每个键存储多个值,则只需要
Any
类型:

scala> val map = collection.mutable.HashMap[String,Any]()
map: scala.collection.mutable.HashMap[String,Any] = Map()

scala> map += "One" -> 1
res1: map.type = Map((One,1))

scala> map += "Two" -> "ii"
res2: map.type = Map((Two,ii), (One,1))

scala> map += "Three" -> None
res3: map.type = Map((Three,None), (Two,ii), (One,1))
您现在可能需要执行模式匹配或使用collect对值执行任何有用的操作:

scala> map.values.foreach(_ match { case i: Int => println("We stored the number "+i) })
We stored the number 1

scala> map.values.collect{ case i: Int => i }
res4: Iterable[Int] = List(1)

如果您使用占位符
\uu
作为类型参数,则会将其转换为存在类型,即,对于某些{type a},您的定义
ListBuffer[\u]
将变为
ListBuffer[a]。这意味着编译器对该类型
A
一无所知,也无法对其进行任何假设

最简单的修复方法是简单地使用
ListBuffer[Any]
并用如下内容包装映射:

val m = new HashMap[String,ListBuffer[Any]]

def get(key: String) =
  m.getOrElseUpdate(key, new ListBuffer())

get("Strings") += "a"
get("Strings") += "b" += "c"
get("Ints") += 1 += 2
// m is now:
// Map(Ints -> ListBuffer(1, 2), Strings -> ListBuffer(a, b, c))

如果您使用占位符
\uu
作为类型参数,则会将其转换为存在类型,即,对于某些{type a}
,您的定义
ListBuffer[\u]
将变为
ListBuffer[a]。这意味着编译器对该类型
A
一无所知,也无法对其进行任何假设

最简单的修复方法是简单地使用
ListBuffer[Any]
并用如下内容包装映射:

val m = new HashMap[String,ListBuffer[Any]]

def get(key: String) =
  m.getOrElseUpdate(key, new ListBuffer())

get("Strings") += "a"
get("Strings") += "b" += "c"
get("Ints") += 1 += 2
// m is now:
// Map(Ints -> ListBuffer(1, 2), Strings -> ListBuffer(a, b, c))

让我再提出一个建议:

import scala.collection.mutable

val map = mutable.Map.empty[String, Vector[Any]].withDefaultValue(Vector.empty)
map("strings") :+= "one"
map("ints") :+= 1
map("ints") ++= Seq(1, 2)

assert {
  map("default") == Vector.empty && // no side effects here
  !map.contains("default")
}

让我再提出一个建议:

import scala.collection.mutable

val map = mutable.Map.empty[String, Vector[Any]].withDefaultValue(Vector.empty)
map("strings") :+= "one"
map("ints") :+= 1
map("ints") ++= Seq(1, 2)

assert {
  map("default") == Vector.empty && // no side effects here
  !map.contains("default")
}
有关允许映射跟踪类型信息的方法,请参阅和。有关允许映射跟踪类型信息的方法,请参阅和。