Целью следующего метода является удаление нулевых значений.
def filterOutNulls[T](items: Iterable[T | Null]): Iterable[T] =
items.collect { case element: T => element }
Код работает во время выполнения, несмотря на предупреждение компилятора: «Проверка типа для T не может быть проверена во время выполнения, поскольку она ссылается на член абстрактного типа или параметр типа».
Добавление ClassTag[T] в качестве параметра контекста устраняет предупреждение, но я думаю, что использование ClassTag в этом случае является излишним.
Вот еще один подход:
def filterOutNulls[T](items: Iterable[T | Null]): Iterable[T] =
items.collect {
case element if element != null => element.asInstanceOf[T]
}
В этом случае требуется asInstanceOf[T], иначе компилятор выдаст сообщение. Очевидно, он игнорирует тот факт, что значение null является единственным экземпляром типа Null.
Ограниченным и неэффективным обходным решением было бы определение экстрактора. Он по-прежнему использует instanceOf, но только один раз, а не каждый match в вашем коде.
object NotNull {
def unapply[T <: AnyRef](scrutinee: T | Null): Option[T] =
if scrutinee == null then None
else Some(scrutinee.asInstanceOf[T])
}
Этот экстрактор ограничен, поскольку он решает только те случаи, когда совпадение не является исчерпывающим.
def filterOutNulls[T](items: Iterable[T | Null]): Iterable[T] =
items.collect {
case NotNull(element) => element
}
Это не применимо к исчерпывающим совпадениям, подобным приведенным ниже.
(nullable: T <: AnyRef) match { // the compiler complains with "not exhaustive"
case NotNull(nonNullable) => Some(nonNullable)
case null => None
}
Компилятор предупреждает, что совпадение не является исчерпывающим. Он недостаточно умен, чтобы заметить, что совпадение на самом деле является исчерпывающим.
Экстрактор также неэффективен, поскольку метод unapply создает экземпляр Some во время выполнения, что я считаю слишком большими накладными расходами с единственной целью подавления ложного предупреждения компилятора.
Что я могу сделать в scala 3.4, чтобы избежать предупреждения о проверке типа без ретрансляции ClassTag или asInstanceOf? Является ли это возможным?
@MateuszKubuszok Спасибо за ссылку. Я прочитал это, но не понимаю, как с помощью TypeTag можно избежать накладных расходов, от которых страдает ClassTag: дополнительный параметр и создание объекта экстрактором. Слишком много накладных расходов во время выполнения только для того, чтобы удалить ложное предупреждение.





Вы можете отключить предупреждение «тест типа для T не может быть проверен во время выполнения, поскольку он относится к члену абстрактного типа или параметру типа» с помощью scala.unchecked
def filterOutNulls[T](items: Iterable[T | Null]): Iterable[T] =
items.collect { case element: T @unchecked => element }
Думаю, вас могут заинтересовать настройки Scala 3.
scalacOptions += "-Yexplicit-nulls"
https://docs.scala-lang.org/scala3/reference/experimental/explicit-nulls.html
Явные значения NULL хорошо работают в некоторых сценариях:
type T
val item: T | Null = null
item match
case null => println("null")
case _ =>
item: T // compiles
println("not null")
// prints: null
if item != null then
item: T // compiles
println("not null")
else println("null")
// prints: null
Проблема в том, что в настоящее время этот вид вывода типа (потоковая типизация) работает со стабильным значением val (как указано выше item).
Мы добавили простую форму вывода типа, чувствительного к потоку. Идея состоит в том, что если
p— это стабильный путь или отслеживаемая переменная, то мы можем знать, чтоpне равно нулю, если сравнивать ее сnull. Эту информацию затем можно передать в ветвиthenиelseоператора if (помимо других мест).
пока element внутри
def filterOutNulls[T](items: Iterable[T | Null]): Iterable[T] =
items.collect {
case element if element != null => element // compile error: Found: (element : T | Null) Required: T
}
не является стабильным.
Вы можете использовать .nn
def filterOutNulls[T](items: Iterable[T | Null]): Iterable[T] =
items.collect {
case element if element != null => element.nn
}
def filterOutNulls[T](items: Iterable[T | Null]): Iterable[T] =
items.collect(Function.unlift(item => Option(item).map(_.nn)))
Я думаю, что ответ на Scala 3: docs.scala-lang.org/scala3/reference/other-new-features/…