Generics 在一种情况下,将Kotlin generic约束为不为null

Generics 在一种情况下,将Kotlin generic约束为不为null,generics,kotlin,Generics,Kotlin,我有一个泛型类型(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>(

我有一个泛型类型(
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?
类存储库{//T可以是非null或可为null的类型。
fun getFromFoo():T{}
fun getFromBar():T{}//这从来都不是空的。我可以这样标记它吗?
}
val repository=repository()
val-fromFoo:String=repository.getFromFoo()//返回非空字符串。
val-fromBar:String=repository.getFromBar()//如何使其工作?
val repository=repository()
val fromFoo:字符串?=repository.getFromFoo()//返回一个可为空的字符串。
val-fromBar:String=repository.getFromBar()//如何使此返回为非空字符串?

理想情况下,我会将它们重构为不同的类型(如
foorrepository
BarRepository
),但有没有办法获得这种类型约束功能?

则相反。假设您的泛型类型不可为null:

class Repository<T> {
  fun getFromFoo(): T? { ... }
  fun getFromBar(): T { ... }
}

val repository = Repository<String>()
val fromFoo: String? = repository.getFromFoo()
val fromBar: String = repository.getFromBar()
类存储库{
fun getFromFoo():T?{…}
fun getFromBar():T{…}
}
val repository=repository()
val fromFoo:字符串?=repository.getFromFoo()
val-fromBar:String=repository.getFromBar()
是一个选项,但它不强制要求
N
为不可为空的类型
是另一个选项,它强制
N
为不可空类型,但不再强制扩展
T
。选择你的毒药


这使得构建存储库变得更加丑陋,但也为您提供了方便,因为它在所有调用站点上都是非空的。

重构为两个单独的类是一个更好的主意,但因为您不希望使用两个泛型类型:

class Repository<T, S: Any> {
    fun getFromFoo(): T? { /* ... */ }
    fun getFromBar(): S { /* ... */ }
}
类存储库{
fun getFromFoo():T?{/*…*/}
fun getFromBar():S{/*…*/}
}

不应使用可为空的类型进行参数化。您应该使用非null类型,然后在真正需要的地方显式地实现null性:

class Repository<out T : Any> {
    fun getFromFoo(): T? {
        TODO()
    }

    fun getFromBar(): T {
        TODO()
    }
}
类存储库{
fun getFromFoo():T{
待办事项()
}
fun getFromBar():T{
待办事项()
}
}

你说
T
应该是一个非空类型(
T:Any
),并且说
getFromFoo()
可能返回
T?
,这非常好。

你需要的是类型
T&Any
——泛型
T
Any
的交叉点。它表示这样的
T
子类型,它永远不能包含空值


不幸的是,在Kotlin中,交集类型,特别是这个交集,目前是不可表示的,这意味着不能将函数的返回类型声明为
t

的不可为null的子类型。那么,存储库的用户不能从非null类型中获得类型安全性好处。考虑ReaviTo.GETFROFFO。这应该会返回一个字符串,但是对于您的代码,它会返回一个字符串吗?不幸的是!也许我遗漏了什么,但从问题来看,这正是你想要的
fromFoo
的返回类型可以根据需要为null,而
fromBar
的返回类型不可以为null。如果存储库使用不可以为null的类型(如字符串)进行参数化,则两个方法都不能返回null。您尝试过吗。。。?注意
T?
的返回类型
getFromFoo
Repository.getFromFoo
的返回类型是
String?
。基本上,语言中有一种方法可以说,即使类被参数化为不可为null的类型,方法也可以返回
null
。例如,
Repository
where
getFromFoo
返回
String?
getFromBar
返回
String
。我想问题是,有没有一种方法可以指示一个方法返回一个不可为null的类型,即使该类是用一个参数化的-简短的回答是否。请查看我对另一个答案的评论。不幸的是,这并不是那么容易。@EricCochran如果评论中的细节是正确的,请编辑这个问题essential@Ilya更新了问题以澄清。OP已经声明这不是他在我的答案评论中想要的。实际上,Kotlin中有一个类型交叉的语法:
fun getFromBar():S其中S:T,S:Any{…}
但在这种特殊情况下,它不会有帮助,因为根本不允许类型与类型参数相交
class Repository<T, S: Any> {
    fun getFromFoo(): T? { /* ... */ }
    fun getFromBar(): S { /* ... */ }
}
class Repository<out T : Any> {
    fun getFromFoo(): T? {
        TODO()
    }

    fun getFromBar(): T {
        TODO()
    }
}