【问题标题】:Get a value from a Scala map with a wildcard key type从具有通配符键类型的 Scala 映射中获取值
【发布时间】:2019-09-03 20:33:50
【问题描述】:

我有一个Map,它的键是一个类的子类型。我无法使用类型为该类实例的变量从地图中获取值。

trait Foo { }

class FooImpl extends Foo {}
class Sample
{
    val m: Map[_ <: Foo, String] =  Map()
    val foo: Foo = new FooImpl

    // This line fails to compile
    m(foo)

    val m2: Map[Foo, String] =  Map()
    // This line compiles fine (but will throw at runtime)
    m2(foo)
}

我使用的是scala 2.12,通配符版本编译失败:

[info] Compiling 1 Scala source to /test/scala/target/scala-2.12/classes ...
[error] /test/scala/src/main/scala/Test.scala:10:7: type mismatch;
[error]  found   : Sample.this.foo.type (with underlying type Foo)
[error]  required: _$1
[error]     m(foo)
[error]       ^
[error] one error found

是否可以在不执行m.filter({(k,v) =&gt; k.equals(foo)}) 之类的操作的情况下从第一个映射 (m) 中获取特定值?在 Java 中,我可以使用 m.get(foo),而 Scala 似乎不太可能迫使我比 Java 更冗长且不够清晰。

澄清。我知道对m2(foo) 的调用将在运行时抛出。在实际情况下,地图包含foo。我的问题是编译错误,而不是运行时错误。

【问题讨论】:

  • val m2: Map[Foo, String] = Map() m2.get(foo) 有什么问题,返回Optionm2(foo) 在运行时抛出异常,因为 m2 为空。在 Java 中 Map&lt;K, V&gt;#get 有不同的签名 V get(Object key)。这将对应于Map[Any, String]
  • 使用m2 的问题是地图来自一个外部库,其类型与我在m 上使用的类型相同。 m.get(foo) 编译失败,出现类似错误。

标签: scala


【解决方案1】:

您需要 Map 的下限类型( >: 而不是 <:>

trait Foo
val foo = new Foo {}
val m: Map[_ >: Foo, String] = Map(foo -> "hi")
m(foo) // String = hi
m.get(new Foo {}) // Option[String] = None

在评论问题之后:假设我们有上限,并希望将其转换为下限

val n: Map[_ <: Foo, String] = Map(foo -> "hi")
n(foo) // does not compile
def upper2lower(x: Map[_ <: Foo, String]): Map[_ >: Foo, String] = Map(x.toSeq:_*)
upper2lower(n)(foo) // String = hi

【讨论】:

  • 鉴于我从外部来源获得了带有 &lt;: 的地图,是否有安全的方法将其转换为该类型?
  • @TroyDaniels,我通过包含转换更新了答案。
  • @VoltyDeQua 实际上在这种特定情况下我们不需要Map[_ &gt;: Foo, String]Map[Foo, String] 似乎就足够了。 Map(new FooImpl {} -&gt; "hi", new Foo {} -&gt; "HI")Map[Foo, String]。转换方法同def upper2lower(x: Map[_ &lt;: Foo, String]): Map[Foo, String] = Map(x.toSeq:_*)
猜你喜欢
  • 2018-09-22
  • 2018-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-12
  • 1970-01-01
  • 2017-02-04
  • 2018-08-21
相关资源
最近更新 更多