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

Scala:如何确定类型是否可为空,scala,nullable,Scala,Nullable,关于Scala中的可空类型,我有两个问题: 假设我想定义一个新类:classmyclass[T](x:T),我想确保T可以为空。我该怎么做 我想编写一个函数def myFunc(x:T)(不是作为上一个问题的一部分),如果T可为空,我想执行一件事,如果不可为空,则执行另一件事。与前面的问题不同的是,这里我不想限制t,而是想知道它是否可以为null。我该怎么做 在scala中,扩展AnyRef(相当于Object)的所有类型都可以为空。不过,大多数scala社区都避免使用空值,并且倾向于通过使用选

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

  • 假设我想定义一个新类:
    classmyclass[T](x:T)
    ,我想确保
    T
    可以为空。我该怎么做

  • 我想编写一个函数
    def myFunc(x:T)
    (不是作为上一个问题的一部分),如果
    T
    可为空,我想执行一件事,如果不可为空,则执行另一件事。与前面的问题不同的是,这里我不想限制
    t
    ,而是想知道它是否可以为null。我该怎么做


  • 在scala中,扩展
    AnyRef
    (相当于
    Object
    )的所有类型都可以为空。不过,大多数scala社区都避免使用空值,并且倾向于通过使用
    选项

    表示值的存在/不存在来更加明确。在scala中,扩展
    AnyRef
    (相当于
    对象
    )的所有类型都可以为空。大多数scala社区都避免使用空值,并且倾向于更明确地使用
    选项表示值的存在/不存在,即使我们在
    scala
    中不使用
    null
    ,通常(有利于
    选项
    )可以强制函数使用空值参数

    def f[T <: AnyRef](x: T) = ???
    

    def[T即使我们在
    Scala
    中不使用
    null
    ,但通常(为了支持
    选项
    ),您可以强制函数使用null参数

    def f[T <: AnyRef](x: T) = ???
    
    def[T1.使用
    >:Null:Null1.使用
    >:Null:Null“Nullable”表示它是
    AnyRef
    的子类(而不是
    Nothing
    ),因此,您可以强制执行
    MyClass
    只接受可为Null的实例,如下所示:

    case class MyClass[T <: AnyRef](t: T)
    
    MyClass("hey")
    MyClass[String](null)
    MyClass(null)
    // MyClass[Int](3) won't compile, because `Int` is primitive
    
    如果您尝试在
    Any
    上使用
    myFunc
    ,这将无法编译,因为编译器将无法确定它是
    AnyRef
    还是
    AnyVal
    ,这两个隐式方法将冲突。这样,就可以确保在编译时不会意外地在
    Any
    上使用
    myFunc
    “Nullable”表示它是
    AnyRef
    的子类(而不是
    Nothing
    ),因此,您可以强制执行
    MyClass
    只接受可为null的实例,如下所示:

    case class MyClass[T <: AnyRef](t: T)
    
    MyClass("hey")
    MyClass[String](null)
    MyClass(null)
    // MyClass[Int](3) won't compile, because `Int` is primitive
    

    如果您尝试在
    Any
    上使用
    myFunc
    ,这将无法编译,因为编译器将无法确定它是
    AnyRef
    还是
    AnyVal
    ,这两个隐式方法将冲突。这样,就可以确保在编译时不会意外地在
    Any
    上使用
    myFunc
    在编译时无法确定其可空性。

    注意,这通常是不够的-
    T
    还必须是可空的
    Null
    的超类型(因为
    Nothing
    不可空)。虽然在您具有传递类型的值的情况下,这可能并不重要。@Vladimitmaveev Good catch!如果签名类似于
    def,则实际上可能很重要[T T=?
    ,因为如果可以区分某物和
    ,则可以在
    情况下跳过
    x
    的计算,而不会引发任何运行时异常。请注意,这在一般情况下是不够的-
    T
    还必须是
    Null
    的超类型才能为Null(因为
    Nothing
    不可为null)。虽然在您有传递类型的值的情况下,这可能并不重要。@VladimirMatveev捕捉得好!如果签名类似于
    def[T],那么它实际上可能很重要=???
    ,因为如果可以区分某物和
    ,则可以跳过
    情况下的
    x
    计算,而不会引发任何运行时异常。
    可为空[any](3)
    返回
    true
    ,这是故意的吗?不,我想我在那里使用了一个不正确的运算符,应该是
    &&
    而不是
    |
    固定的。
    可以为空[Any](3)
    返回
    true
    ,这是故意的吗?不,我想我在那里使用了一个不正确的运算符,应该是
    &
    而不是
    |
    固定的。
    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("hello")
    myFunc(null)
    myFunc(42)
    
    // outputs:
    // that's a non-null object: hello
    // that's a null
    // That's an AnyVal: 42