我有两个关于Scala中可空类型的问题:
我想说我希望定义一个新类:class myClass[T](x: T)
,并且我想确保T
可以为空。我该怎么做?
我想编写一个函数def myFunc(x: T)
(不是上一个问题的一部分),如果T
可以为空,我想执行一项操作或者如果不是。与前一个问题的不同之处在于,我不希望限制T
,而是知道它是否可以为空。我该怎么做?
答案 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) = ???