Scala 2.8 изменяемый - PullRequest
       1

Scala 2.8 изменяемый

2 голосов
/ 30 июня 2010

Используя 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 ]

4 голосов
/ 01 июля 2010

В Scala 2.7.7 вы сразу получаете NullPointer при добавлении нуля:


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...

Используя Scala 2.8.0.RC7, это уже не так.Однако, как заметил Рэндалл , поведение также не совсем соответствует:

<code>
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)<code> returns zero if the elem is <code>null.Таким образом, в этом случае элемент с нулевым индексом «инициализируется» значением null (которое уже имело значение), но tableSize увеличивается.Это объясняет результаты, которые видны в REPL.

Если вы вызываете head на множестве, в конечном счете вызывается итератор в FlatHashTable, как видно из трассировки стека.Это реализовано следующим образом:


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 вернет false, поскольку элемент, который мы сохранили в массиве, имеет значение null, поэтому вызов next вызовет Iterator.empty.next , что вызывает исключение.Поскольку добавление нулевого в HashSet не выполняется последовательно в Scala 2.8, это действительно выглядит как ошибка.Кроме того, как уже отмечалось, это дает еще одну вескую причину не использовать ноль , где это возможно.

Edit Поскольку я не смог найти для этого билет, я добавил это .

3 голосов
/ 01 июля 2010

Возможно, это ошибка, но это то, что я наблюдаю в 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...