在一种情况下,将Kotlingenerics约束为非null

我有一个genericstypes( T: Any? ),我需要约束在一种情况下永远不会为null

 class Repository { // 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() val fromFoo: String = repository.getFromFoo() // Returns a non-null String. val fromBar: String = repository.getFromBar() // How do I make this work? val repository = Repository() val fromFoo: String? = repository.getFromFoo() // Returns a nullable String. val fromBar: String = repository.getFromBar() // How do I make this return a non-null String? 

虽然我会理想地将这些重构成单独的types(如FooRepositoryBarRepository ),有什么办法来获得这种types的约束function?

你需要的是typesT & Any – genericsTAny的交集。 它代表了T不能包含空值的T子types。

不幸的是,交集types和这个交集特别是在Kotlin中是不可指定的,这意味着你不能将函数的返回types声明为T非可为子types。

做相反的事情。 假设您的genericstypes不可为空:

 class Repository { fun getFromFoo(): T? { ... } fun getFromBar(): T { ... } } val repository = Repository() val fromFoo: String? = repository.getFromFoo() val fromBar: String = repository.getFromBar() 
 class Repository { // 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() val fromFoo: String? = repository.getFromFoo() val fromBar: String = repository.getFromBar() 

需要一个非nulltypes。 你可以通过T?选择性地指出可空性T? vs你的方法/属性。

编辑:根据评论中的问题澄清修订的解决方案

我现在的印象是,你想要一个方法总是返回一个非空值,即使T是一个可为空的types。 简短的答案是否定的,没有办法做到这一点。

但是,您可以定义两种generics:

  class Repository { fun getFromFoo(): T {} fun getFromBar(): N {} } val repository = Repository() val fromFoo: String? = repository.getFromFoo() val fromBar: String = repository.getFromBar() 

是一个选项,但不强制N是非空types的。 是另一种选择,这迫使N是一个不可空的types,但它不再被迫扩展T 选择你的毒药。

这使得构建存储库丑陋,但让你容易在所有的调用网站非空。

您不应该使用可为空的types进行参数化。 您应该使用非nulltypes,然后在真正需要的地方明确可空性:

 class Repository { fun getFromFoo(): T? { TODO() } fun getFromBar(): T { TODO() } } 

你说T应该是一个非空types( T: Any ),并且说getFromFoo()可能返回T? ,这工作完全正常。

重构为两个单独的类将是一个更好的主意,但是由于您不希望可以使用两个genericstypes:

 class Repository { fun getFromFoo(): T? { /* ... */ } fun getFromBar(): S { /* ... */ } }