代码之家  ›  专栏  ›  技术社区  ›  ScootyPuff

Scala 2.8可变。设置空处理

  •  2
  • ScootyPuff  · 技术社区  · 14 年前

    使用scala 2.8:

    import scala.collection.mutable
    import mutable.MultiMap
    val m = new mutable.HashMap[String, mutable.Set[String]] with MultiMap[String, String]
    m.addBinding("key", null)
    m exists { _._2 contains null }
    

    m exists { _._2 isEmpty }
    

    m("key").size
    

    打印1

    如何找到通过addBinding调用添加的值为null的第一个键(或任何键)?

    2 回复  |  直到 14 年前
        1
  •  4
  •   Community CDub    8 年前

    在Scala 2.7.7中,添加null时会直接得到null指针:

    
    scala> val s = new scala.collection.mutable.HashSet[String]
    s: scala.collection.mutable.HashSet[String] = Set()
    
    scala> s += null
    java.lang.NullPointerException
        at scala.collection.mutable.FlatHashTable$class.elemHashCode(FlatHashTable.scala:144)
        at scala.collection.mutable.HashSet.elemHashCode(HashSet.scala:31)
        at scala.collection.mutable.FlatHashTable$class.addEntry(FlatHashTable.scala:66)
        at scala.collection.mutable.HashSet.addEntry(HashSet.scala:31)
        at scala.collection.mutable.HashSet.$plus$eq(HashSet.s...
    

    使用scala2.8.0.RC7,情况就不再是这样了。然而,作为 Randall has observed ,行为也不完全一致:

    
    scala> import scala.collection.mutable.HashSet
    import scala.collection.mutable.HashSet
    
    scala> val s = new HashSet[String]
    s: scala.collection.mutable.HashSet[String] = Set()
    
    scala> s += null
    res0: s.type = Set()
    
    scala> s += null
    res1: s.type = Set()
    
    scala> s.size
    res2: Int = 2
    
    scala> s.head
    java.util.NoSuchElementException: next on empty iterator
        at scala.collection.Iterator$$anon$3.next(Iterator.scala:29)
        at scala.collection.Iterator$$anon$3.next(Iterator.scala:27)
        at scala.collection.mutable.FlatHashTable$$anon$1.next(FlatHashTable.scala:176)
        at scala.collection.IterableLike$class.head(IterableLike.scala:102)
        at scala.collection.mutable.HashSet.head(HashSet.scala:38)
        at .(:8)
    

    添加条目时的大部分工作都是在中完成的 FlatHashTable addEntry 调用,如下所示:

    
     /** The actual hash table.
     */
     @transient protected var table: Array[AnyRef] = new Array(initialCapacity)
    
    def addEntry(elem: A) : Boolean = {
      var h = index(elemHashCode(elem))
      var entry = table(h)
      while (null != entry) {
      if (entry == elem) return false
          h = (h + 1) % table.length
          entry = table(h)
     }
     table(h) = elem.asInstanceOf[AnyRef]
     tableSize = tableSize + 1
     if (tableSize >= threshold) growTable()
        true
     }
    

    null.asInstanceOf[AnyRef] 只是还给你 null elemHashCode(elem) returns zero if the elem is null . So in this case, the element with index zero is 'initialized' with null (which is the value it already had), but the tableSize is increased. This explains the results that are seen in the REPL.

    如果你打电话 head FlatHashTable 调用,从stacktrace可以看出。具体实施如下:

    
    iterator = new Iterator[A] {
      private var i = 0
      def hasNext: Boolean = {
        while (i < table.length && (null == table(i))) i += 1
        i < table.length
      }
      def next(): A =
        if (hasNext) { i += 1; table(i - 1).asInstanceOf[A] }
        else Iterator.empty.next
    }
    

    hasNext next 将调用Iterator.empty.next,这将引发异常。

    编辑 因为我找不到这张票,我 added it .

        2
  •  3
  •   Randall Schulz    14 年前

    也许这是一个bug,但我在Scala 2.8.RC3中观察到:

    scala> import scala.collection.mutable.HashSet
    import scala.collection.mutable.HashSet
    
    scala> val hs1 = new HashSet[String]
    hs1: scala.collection.mutable.HashSet[String] = Set()
    
    scala> hs1 += null
    res0: hs1.type = Set()
    
    scala> hs1.size
    res1: Int = 1
    
    scala> hs1.contains(null)
    res2: Boolean = false