【问题标题】:Return type is different when invoking the same method on different objects在不同对象上调用相同方法时返回类型不同
【发布时间】:2018-02-07 23:13:27
【问题描述】:

我编写了以下应用程序:

  var counters: mutable.Map[String, mutable.Map[String, Long]] = mutable.Map()
  counters("key1") = mutable.Map("counters_key"→ 20)
  counters("key2") = mutable.Map("counters_key" → 920)
  counters("key3") = mutable.Map("counters_key" → 920)
  counters("key4") = mutable.Map("counters_key" → 920)
  counters("key5") = mutable.Map("counters_key" → 920)

  var counters2: mutable.Map[String, mutable.Map[String, Long]] = mutable.Map()
  counters2("key1") = mutable.Map("counters2_key_1"→ 112000, "counters_key_2" → 1112000, "counters_key_3"→ 20)
  counters2("key2") = mutable.Map("counters2_key_4" → 9112000, "counters_key_5" → 91112000, "counters_key_6" → 920)

  val flattenedCounters =  counters.toMap.values.flatten
  val flattenedCounters2 = counters2.toMap.values.flatten

  println(flattenedCounters.getClass == flattenedCounters2.getClass) 
  //true

  println(flattenedCounters.groupBy(_._1).getClass == 
          flattenedCounters2.groupBy(_._1).getClass) 
  //false

DEMO

我们在两个相同类型的对象上调用相同的方法。但它给了我们不同类型的对象。为什么?

【问题讨论】:

    标签: scala collections


    【解决方案1】:

    关键在于计数器的大小

       val map = counters.toMap
       println(map.getClass)
       //class scala.collection.immutable.HashMap$HashTrieMap
       println(map.size)
       //5
    
       val map2 = counters2.toMap
       println(map2.getClass)
       //class scala.collection.immutable.Map$Map2
       println(map2.size)
       //2
    

    看起来 Scala 有几个Map 的实现。 Map2 被优化为恰好容纳 2 个元素。并且有优化的实现高达Map4

    你可以在sources找到这些课程

    当您调用toMap 时,它会创建新的构建器来保存空地图。 然后将每个元素添加到地图中。

    • 空映射 + 新键是 Map1 src
    • Map1 + 新键是 Map2 src
    • ...
    • Map4 + 新键为 HashMap src

    【讨论】:

    • 非常有趣...实际类型取决于元素的数量。 This deme 仍然显示出差异。但是this one 返回相同的结果......仍然有点不清楚这怎么可能。
    • 添加了更多对来源的引用
    • @NazariiBardiuk 的列表在immutable.HashMap 中继续,其中包括HashMap1HashTrieMapHashMapCollision,这反过来又涵盖了更大范围的“小”不可变映射。哲学实际上很简单:区别对待小集合。由于多态性,它们可以为每种尺寸提供不同的版本。如果你想知道血淋淋的细节,你必须阅读链接的来源。这不是一个愉快的阅读,这是肯定的。 (+) 用于 Nazarii 的研究工作
    • 非常有趣的研究!非常感谢。
    【解决方案2】:

    正如@Nazarii Bardiuk 所指出的,这是由于不可变地图大小的差异。 Scala 通过将小型 Map 存储为单个对象并将元素作为字段来优化它们,并将较大的 Map 实现为 HashMap,它使用 HashTrieMap

    这是来自相关Scala doc 部分Hash Tries 下的引用:

    Scala 对不可变集合和映射进行了进一步优化, 包含少于五个元素。一到四个集合和地图 元素存储为仅包含元素的单个对象 (或在地图的情况下键/值对)作为字段。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-25
      • 2013-08-14
      • 1970-01-01
      • 1970-01-01
      • 2015-02-05
      相关资源
      最近更新 更多