【问题标题】:How to combine Maps with different value types in Scala如何在 Scala 中将 Maps 与不同的值类型结合起来
【发布时间】:2015-08-03 07:35:27
【问题描述】:

我有以下正在运行的代码:

case class Step() {
  def bindings(): Map[String, Any] = ???
}

class Builder {
  private val globalBindings = scala.collection.mutable.HashMap.empty[String, Any]
  private val steps = scala.collection.mutable.ArrayBuffer.empty[Step]

  private def context: Map[String, Any] =
    globalBindings.foldLeft(Map[String, Any]())((l, r) => l + r) ++ Map[String, Any]("steps" -> steps.foldLeft(Vector[Map[String, Any]]())((l, r) => l.+:(r.bindings)))
}

但我认为它可以被简化,以便在 'context' 方法中不需要第一个 foldLeft。

所需的结果是生成一个映射,其中条目值是字符串、稍后将在其上调用 toString 的对象或返回字符串的函数。

这是我能用 Scala 的类型系统做的最好的事情,还是我可以让代码更清晰?

TIA

【问题讨论】:

  • 最好在 99% 的情况下远离 Any — 你不再编写 Java 了:)
  • 为什么值类型必须不同?他们不都评估为String 吗?它可以是一个评估String的函数。该函数应该能够处理如何评估给定字符串值的逻辑。

标签: scala generics collections types


【解决方案1】:

首先,mutable.HashMap 上的 toMap 方法返回一个 immutable.Map。如果你真的需要一个向量,你也可以使用map 而不是内部的foldLefttoVector,这可能是不必要的。最后,您可以使用+ 将所需的“步骤”键值对添加到地图中。

所以你的整个方法体可能是:

globalBindings.toMap + ("steps" -> steps.map(_.bindings).toVector)

我还要注意,您应该担心在 Scala 中使用像 Map[String, Any] 这样的类型。 Scala 的强大功能很大程度上来自于它的类型系统,它可以在许多此类情况下发挥出色的效果,因此这些类型通常被认为是单一的。当然,在某些情况下这种方法最有意义,如果没有更多上下文,很难确定这是否正确。

【讨论】:

  • 太棒了,谢谢。我知道 Any 是一种气味,只是不知道如何纠正它。 val 声明呢,例如globalBindings,它们可以用其他方式编写还是必须具有 Any 类型,因为它们可以是 String、toStringable 或 (=> String) 函数?
  • 您可以创建一个包含所有这些类型的包装器特征,然后将其用作映射的值类型。
  • 听起来不错,但是突破了我的 Scala-foo 的极限,你能给我更多的指点吗?你的意思是像workday.github.io/scala/2015/02/05/scala-typesafe-wrappers
猜你喜欢
  • 1970-01-01
  • 2013-03-05
  • 1970-01-01
  • 2011-10-04
  • 1970-01-01
  • 2022-11-02
  • 2011-03-15
  • 2019-08-03
  • 1970-01-01
相关资源
最近更新 更多