聊一聊泛型的可空性 (kotlin)
什么?泛型本身也可以是nullable?上来就抛这么个问题实在是不够友好~
首先回顾,什么是泛型?Oracle Java Tutorials
Introduced in J2SE 5.0, this long-awaited enhancement to the type system allows a type or method to operate on objects of various types while providing compile-time type safety. It adds compile-time type safety to the Collections Framework and eliminates the drudgery of casting.
泛型的本质是参数化类型,也就是说操作的数据类型被指定为一个参数。简单来讲,泛型就是操作类型的占位符。
那,为什么要使用泛型?Oracle Java Tutorials
In a nutshell, generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods. Much like the more familiar formal parameters used in method declarations, type parameters provide a way for you to re-use the same code with different inputs. The difference is that the inputs to formal parameters are values, while the inputs to type parameters are types.
泛型的好处是在编译的时候做类型安全检查,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
在深入讨论泛型的可空性之前,首先看一个简单的例子 (kotlin中更多泛型的介绍,以及其与java泛型的区别,可以查看Generics)
fun <T> whoAmI(t: T) { val clazz = t::class println("I'm $clazz") }
上面的代码是编译不过的,问题在于
nullable type 'T'
是什么鬼?OK,我们按照提示,为参数t加上!!
强制标识为not-null (关于!!
的使用,可以查看Null Safety)
WTF~ 哔~ 卒~
在继续讨论之前,先关注两个概念,type parameter
和type argument
,在一个函数中,前者是函数参数的类型(类型),如translate(java.lang.String, java.lang.String)
中的java.lang.String
,而后者则是函数调用时传入的具体值(类型),如translate("Hello You!", "zh-cn")
中的Hello You
及zh-cn
,泛型作为一个占位符,占的正是type parameter
的位
首先简单了解一下argument
的可空性,kotlin中控制函数参数值(类属性值等)的nullable是通过?
符号实现的,默认均为non-nullable,如以下代码片段是编译不过的
只有指定参数name
为nullable,才可以顺利编译
同样,对应泛型类,我们也可以指定nullable及non-nullable的type argument
从上例中可以看到,null
在kotlin中的类型为Nothing?
(kotlin中一切皆为对象)
更多内容请参考 Null Safety
说了这么多,到底什么是泛型的可空性(type argument
的nullable
)?
上例中,之所以可以将forestA
指定为Forest<Tree?>
,是因为,每一个nullable
的type argument
都有一个隐式边界Any?
,即如下两种类声明完全等价
// T的隐式边界为Any? class Forest<T> // 显示指定T的边界为Any? class Forest<T : Any?> // 显示指定T的边界为Tree? class Forest<T : Tree?>
如果将Forest
中的泛型强制指定为non-nullable会发生什么
什么?不能将nullable的Tree?
应用到Forest
类了!这是因为Forest
类的定义中,我们强制将泛型的边界指定为了non-nullable的Tree
所以,回到文章的开头,函数whoAmI
的错误信息nullable type 'T'
指的是哪个鬼?泛型T
的默认边界为Any?
,即T : Any?
,所以,我们只需要显示指定T
为non-nullable即可
至此,对于nullable
及non-nullable
的type parameter
及type argument
是否有所了解?