Scala:如何确定类型是否可为空

时间:2018-02-09 20:56:13

标签: scala nullable

我有两个关于Scala中可空类型的问题:

  1. 我想说我希望定义一个新类:class myClass[T](x: T),并且我想确保T可以为空。我该怎么做?

  2. 我想编写一个函数def myFunc(x: T)(不是上一个问题的一部分),如果T可以为空,我想执行一项操作或者如果不是。与前一个问题的不同之处在于,我不希望限制T,而是知道它是否可以为空。我该怎么做?

4 个答案:

答案 0 :(得分:4)

在scala中,所有扩展AnyRef(相当于Object)的类型都可以为空。大多数scala社区虽然避免使用空值,但通过用Option表示值的存在/不存在往往更明确。

答案 1 :(得分:3)

1。使用>: Null <: AnyRef绑定:

@ def f[T >: Null <: AnyRef](arg: T): T = arg
defined function f

@ f(10)
cmd3.sc:1: inferred type arguments [Any] do not conform to method f's type parameter bounds [T >: Null <: AnyRef]
val res3 = f(10)
           ^
cmd3.sc:1: type mismatch;
 found   : Int(10)
 required: T
val res3 = f(10)
             ^
Compilation Failed

@ f("a")
res3: String = "a"

2。使用具有默认值的隐式类型约束:

@ def isNullable[T](arg: T)(implicit sn: Null <:< T = null, sar: T <:< AnyRef = null): Boolean = sn != null && sar != null
defined function isNullable

@ isNullable(10)
res8: Boolean = false

@ isNullable("a")
res9: Boolean = true

这些类似于静态类型边界,除了它们是在隐式解析而不是类型检查期间执行的,因此如果为它们提供默认值则允许失败(在这种情况下为null s,没有双关语意图:) )

答案 2 :(得分:3)

“Nullable”表示它是AnyRef(而不是Nothing)的子类,因此,您可以强制MyClass只接受可为空的实例,如下所示:

case class MyClass[T <: AnyRef](t: T)

MyClass("hey")
MyClass[String](null)
MyClass(null)
// MyClass[Int](3) won't compile, because `Int` is primitive

要确定某个类型是否可为空,您可以提供生成可空性标记的隐式方法:

sealed trait Nullability[-T]
case object Nullable extends Nullability[AnyRef] {
  def isNull(t: Any): Boolean = t == null
}
case object NotNullable extends Nullability[AnyVal]
object Nullability {
  implicit def anyRefIsNullable[T <: AnyRef]: Nullability[T] = Nullable
  implicit def anyValIsNotNullable[T <: AnyVal]: Nullability[T] = NotNullable
}

def myFunc[T](t: T)(implicit nullability: Nullability[T]): Unit = {
  nullability match {
    case Nullable => 
      if (t == null) {
        println("that's a null")
      } else {
        println("that's a non-null object: " + t)
      }
    case NotNullable => println("That's an AnyVal: " + t)
  }
}

现在您可以使用myFunc,如下所示:

myFunc("hello")
myFunc(null)
myFunc(42)

// outputs:
// that's a non-null object: hello
// that's a null
// That's an AnyVal: 42

如果您尝试在myFunc上使用Any,则无法编译,因为编译器无法确定它是AnyRef还是AnyVal,以及这两个隐式方法会发生冲突。通过这种方式,可以在编译时确保我们不会在myFunc上意外使用Any,因为在编译时无法确定可为空性。

答案 3 :(得分:2)

即使我们在null中不使用Scala经常(赞成Option),您也可以强制函数使用

来获取可为空的参数
def f[T <: AnyRef](x: T) = ???