以下方法的目的是去除空值
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
?可以吗?
您可以使用
scala.unchecked
关闭警告
def filterOutNulls[T](items: Iterable[T | Null]): Iterable[T] =
items.collect { case element: T @unchecked => element }
我想你可能对设置感兴趣
scalacOptions += "-Yexplicit-nulls"
https://docs.scala-lang.org/scala3/reference/experimental/explicit-nulls.html
这在某些场景下有效
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,而
element
in
def filterOutNulls1[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)))