Самое большое различие - то, что усеченный не зарегистрированная операция, в то время как удаляют.
Просто это означает, что в случае катастрофического отказа базы данных, Вы не можете восстановить данные, управляемые на усеченным, но с удаляют Вас, может.
[еще 113] детали здесь
Вы можете воспользоваться тем фактом, что Scala уже предоставляет вам способ получения значения типа по умолчанию. Когда вы пишете var x: Int = _
, это инициализирует x
в 0
. Аналогично для всех типов AnyVal
. Все типы AnyRef
инициализируются значением null
.
Имея это в виду, вы можете переписать свой разреженный векторный класс следующим образом:
class SparseVector[T](val size: Int) {
import scala.collection.mutable.Map
private var default: T = _
private[this] val storage = Map[Int, T]()
def apply(key: Int) =
if(key < size)
storage.getOrElse(key, default)
else
throw new IllegalArgumentException("Index " + key + " out of bounds")
def update(key: Int, value: T) { storage(key) = value }
}
Теперь код, подобный следующему, работает должным образом:
scala> val b = new SparseVector[Boolean](10)
b: SparseVector[Boolean] = SparseVector@cfd22a
scala> b(1)
res20: Boolean = false
scala> b(1) = true
scala> b(1)
res22: Boolean = true
scala> val i = new SparseVector[Int](10)
i: SparseVector[Int] = SparseVector@1813c12
scala> i(1)
res23: Int = 0
scala> i(1) = 10
scala> i(1)
res25: Int = 10
scala> i(10)
java.lang.IllegalArgumentException: Index 10 out of bounds
Несколько улучшений, которые я мог бы внести в этот класс:
object SparseVector {
def apply[T](size: Int) = new SparseVector[T](size)
def apply[T](size: Int, default: T) = {
val result = new SparseVector[T](size)
result.default = default
result
}
}
Теперь это работает:
scala> val b = SparseVector[Boolean](10, true)
b: SparseVector[Boolean] = SparseVector@126f29f
scala> b(4)
res28: Boolean = true
scala> val i = SparseVector[Int](10, 42)
i: SparseVector[Int] = SparseVector@b9979b
scala> i(3)
res30: Int = 42
РЕДАКТИРОВАТЬ: Написанный мной код работает с Scala 2.7.6.final. Митч Блевинс указал, что код дает null
в качестве значения по умолчанию для типов AnyVal
при запуске с Scala 2.8r.19890. Как объясняется в комментариях, это невозможно, поскольку Null
не является подтипом AnyVal
. Общая идея должна быть аналогичной при использовании 2.8, например var b: Boolean = _
должен по-прежнему давать значение по умолчанию для типа Boolean
. Использование коллекций для хранения разреженного вектора может быть другим, но, как я сказал в комментарии, я не знаком с редизайном коллекции 2.8.
EDIT2: ... null
поведение не должно быть возможным, но, к сожалению, это так. При проведении дополнительных исследований проблемы выяснилось, что из-за стирания типа поле default
всегда инициализируется значением null
. А после этого ... начинаются странности. См. сообщение Митча для обсуждения и некоторого кода медвежьей кости, воспроизводящего проблему.
Вещи, которые я пробовал и потерпел неудачу, чтобы заставить код работать должным образом:
null.asInstanceOf [T]
- нет, в Java нет обобщенных дженериков. Это по-прежнему дает null
@specialized
- нет, кажется, даже если компилятор сгенерирует специализированный код для примитивов, вы все равно получите нулевое поведение AnyVal
, который не должен быть нулевым
. Нет. По-прежнему null
. Итак, концептуально мое решение должно работать.
Вы можете использовать манифест, чтобы получить то же значение по умолчанию, что и для Array
, что позволяет избежать необходимости указывать собственные имплициты. Снова заимствуя остальную часть кода у Дэвида Уинслоу,
class SparseVector[T](size: Int)(implicit manifest: Manifest[T]) {
private val default = manifest.newArray(1)(0)
private var storage = scala.collection.mutable.Map[Int, T]()
def apply(i: Int) = storage.getOrElse(i, default)
def update(i: Int, v: T) = storage.update(i, v)
}
Затем просто,
val v = new SparseVector[Int](100)
println( v(12) ) // prints '0'
и т. Д.
Повторно используя класс Дэвида SparseVector, вы можете использовать что-то вроде этого:
class SparseVector[T](size: Int, default: T = 0) {
private var storage = scala.collection.mutable.Map[Int, T]()
def apply(i: Int) = storage.getOrElse(i, default)
def update(i: Int, v: T) = storage.update(i, v)
}
object SparseVector {
implicit def svInt2String(i: Int) = "default"
implicit def svInt2Boolean(i: Int = false
}
Вам нужно импортировать имплициты, что досадно, но это дает вам: -
import SparseVector._
val v = new SparseVector[Int](100)
println( v(12) ) // prints '0'
val w = new SparseVector[Double](100)
println( w(12) ) // prints '0.0'
val x = new SparseVector[Boolean](100)
println( x(85) ) // prints 'false'
val y = new SparseVector[String](100)
println( y(85) ) // prints 'default'
Вы можете добавить неявный аргумент в качестве второго параметра в конструктор:
class SparseVector[A](size: Int) (implicit default: () => A) {
private var storage = scala.collection.mutable.Map[Int, A]()
def apply(i: Int) = storage.getOrElse(i, default())
def update(i: Int, v: A) = storage.update(i, v)
}
implicit def strDefault(): String = "default"
И указать имплициты для типов, которые вам нужны. Это также позволяет вызывающим абонентам предоставлять свои собственные значения по умолчанию, передавая свои собственные значения по умолчанию в:
val sparseWithCustomDefault = new SparseVector[String](10) (() => "dwins rules!");