2015-01-31 26 views
2

Kotlin有漂亮的功能(?.!!.)处理可为空的类型。但是这个只是打击了我 - 如果你不知道你是在处理可为空还是不可为空的类型呢?如果你有泛型类MyClass<T>,那么你只是有一些类型T,就是这样。可以在泛型类中使用可为空的运算符吗?

不科特林允许有适用于通用型(T这里)“可空”的运营商,也可制成型为空的类(如T?),以及如果该类将可空类型的实例化 - 像MyClass<String?>。是否会在MyClass类型中导致可空(例如指向C++中指针的指针 - **std::string)类型的空?

+0

只是键入'T'被解释为'T:Any?',所以没有“只输入'T'”,因为编译器会将其视为可空。您可以使用'T:Any'来定义不可空的不同上限。 – 2016-01-02 03:21:30

回答

5

我刚刚在Web Demo中试过。

class MyClass<T>(val x: T) { 
    fun foo() { 
    println(x.toString()) 
    } 

    fun fooSave() { 
    println(x?.toString()) 
    } 

} 

fun main(args: Array<String>) { 
    MyClass<String?>(null).fooSave() 
    MyClass<String?>(null).foo() 
} 

看来你可以随时申请空安全操作员?.,即使类型不一定为空。

在另一方面,你可以泛型类型参数T绑定到一个可空类型,在我的情况String? 这实际上如果你通过 null 会产生一个NullPointerException异常。

编辑:由于问题被问到,没有上限的泛型类型的语义已经改变。现在将T解释为T : Any?。但是,上面的代码不会崩溃了。原因是呼叫x.toString()将调用正确处理null的扩展功能Any?.toString()

如果我们改变了代码如下

class MyClass<T : Any>(val x: T) { 
    fun foo() { 
    println(x.toString()) 
    } 

    fun fooSave() { 
    println(x?.toString()) 
    } 

} 

fun main(args: Array<String>) { 
    MyClass<String?>(null).fooSave() 
    MyClass<String?>(null).foo() 
} 

现在甚至不进行编译,因为我们不能String?实例T : Any。呼叫x?.toString()也标有警告,表示安全呼叫是不必要的。

+0

哇,如果我可以,我会为该链接添加更多点:-)非常感谢。更重要的是 - 你刚刚发现,针对null的显式实际上并不起作用。如果没有泛型,你将不得不编写'!!。toString()',但是泛型编译器不知道'T'是什么,并且允许隐式检查。 – greenoldman 2015-02-01 14:01:51

+1

第二次检查时,这个例子是特例,因为toString是在根类型中定义的。这就是为什么(可能)它首先编译的原因 - 任何其他方法(如“length”)都需要为泛型添加约束,这意味着您必须事先决定您编写泛型类的类型 - 可为空还是不可以。 – greenoldman 2015-02-01 14:43:09

+1

你说得对。如果我设置T来扩展任何类型,我不能将它绑定到可空类型,因为T?不延伸T.这是一个不能编译的例子:http://kotlin-demo.jetbrains.com/?publicLink=1174338469563409828491677856014 – 2015-02-01 14:46:29

相关问题