如何避免可空类型的模式匹配中出现“类型测试无法检查”的警告?

问题描述 投票:0回答:1

以下方法的目的是去除空值

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 scala-3
1个回答
0
投票

您可以使用

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)))
© www.soinside.com 2019 - 2024. All rights reserved.