我有一个泛型类型(T: Any?
),我需要在一种情况下约束null
:
class Repository<T> { // T may be a non-null or nullable type.
fun getFromFoo(): T {}
fun getFromBar(): T {} // This is never null. Can I mark it as so?
}
val repository = Repository<String>()
val fromFoo: String = repository.getFromFoo() // Returns a non-null String.
val fromBar: String = repository.getFromBar() // How do I make this work?
val repository = Repository<String?>()
val fromFoo: String? = repository.getFromFoo() // Returns a nullable String.
val fromBar: String = repository.getFromBar() // How do I make this return a non-null String?
虽然我理想地将这些重构为单独的类型(例如FooRepository
和BarRepository
),但有没有办法获得此类型约束功能?
答案 0 :(得分:3)
您需要的是T & Any
类型 - 通用T
和Any
的交集。它表示T
的这种子类型,它永远不能包含空值。
不幸的是,交集类型和此交集特别是当前在Kotlin中是不可表示的,这意味着您不能将函数的返回类型声明为T
的非可空子类型。
答案 1 :(得分:2)
反其道而行之。假设您的泛型类型不可为空:
class Repository<T> {
fun getFromFoo(): T? { ... }
fun getFromBar(): T { ... }
}
val repository = Repository<String>()
val fromFoo: String? = repository.getFromFoo()
val fromBar: String = repository.getFromBar()
答案 2 :(得分:2)
class Repository<T : Any> { // T may only be a non-null type.
fun getFromFoo(): T? {} // This may return null.
fun getFromBar(): T {} // This is never null.
}
val repository = Repository<String>()
val fromFoo: String? = repository.getFromFoo()
val fromBar: String = repository.getFromBar()
需要非null类型。您可以通过T?
vs T
为您的方法/属性选择性地指明可为空性。
编辑:根据评论中的问题澄清修订解决方案
我现在的印象是,您希望一个方法始终返回非空值,即使T是可空类型。简短的回答是否定的,没有办法做到这一点。
但是,您可以定义两个泛型:
class Repository<T, N : T> {
fun getFromFoo(): T {}
fun getFromBar(): N {}
}
val repository = Repository<String?, String>()
val fromFoo: String? = repository.getFromFoo()
val fromBar: String = repository.getFromBar()
<T, N : T>
是一种选择,但它并不强制N
属于非可空类型。 <T, N : Any>
是另一种选择,这会强制N
为非可空类型,但不再强制扩展T
。选择你的毒药。
这使得构建存储库变得更加丑陋,但让您在所有呼叫站点都非常无效。
答案 3 :(得分:1)
您不应该使用可空类型进行参数化。您应该使用非null类型,然后在真正需要的地方明确可空性:
class Repository<out T : Any> {
fun getFromFoo(): T? {
TODO()
}
fun getFromBar(): T {
TODO()
}
}
你说T
应该是非空类型(T: Any
),并说getFromFoo()
可能会返回T?
,这完全正常。< / p>
答案 4 :(得分:0)
重构为两个单独的类是一个更好的主意,但因为你不希望你可以使用两种泛型类型:
class Repository<T, S: Any> {
fun getFromFoo(): T? { /* ... */ }
fun getFromBar(): S { /* ... */ }
}