Kotlin 流出泛型

Kotlin Flow out generic

我正在使用 flow{} 生成器调用 api,然后 emit() 响应 ViewModel。我将 return 类型的流添加为 Flow<Resource<List<RemoteData>>>。但是,在 emit() 的某些地方,Android Studio 抛出

error : Not enough information to infer type variable T

因为 emit(Resource.Error(message = "Couldn't reach server, check your internet connection.")) 需要 List<RemoteData> 类型的值 请参阅下面我的 Resource class

sealed class Resource<T>(val data: T? = null, val message: String? = null) {
    class Loading<T>(data: T? = null): Resource<T>(data)
    class Success<T>(data: T?): Resource<T>(data)
    class Error<T>(message: String, data: T? = null): Resource<T>(data, message)
}

我的问题,将 emit 更改为

是否安全
emit(Resource.Error(
            message = "Couldn't reach server, check your internet connection.",
            data = null
        ))

流的 return 类型为 Flow<Resource<out List<RemoteData>>> ?

Kotlin 有声明站点差异。我会将 out 放在资源 class 声明中。然后当你声明你的类型 Flow<Resource<List<RemoteData>>> 时,它已经是隐式的 out List<RemoteData>.

此外,您的资源 class 对我来说看起来很复杂。如果 data 是加载的资源,它不应该是 Loading 或 Error classes 的一部分。为什么强制 Loading 和 Error 的每个实例都携带一个无意义的 null data 值?同样,message 不应该是 Loading 和 Success 案例的一部分。

我会像这样将您的密封 class 重写为密封接口(因为它在类型之间没有共享状态),并利用数据 class 功能。 Loading 可以是 object 因为它不需要保持状态。 Loading 和 Error 都可以是 Resource<Nothing> 因为类型 T 与它们的任何特定实例无关。这样你就不必在使用它们时不必要地指定类型,比如必须在 when 语句中的 is Resourceis Error 之后放置 <RemoteData>

sealed interface Resource<out T> {
    object Loading: Resource<Nothing>
    data class Success<out T>(val data: T): Resource<T>
    data class Error(val message: String): Resource<Nothing>
}

这个版本的密封classes会更容易使用。编译器将更宽松地处理您需要指定泛型类型的方式和位置。