我用
标记了这个网络响应类sealed class NetworkResponse<out T> {
data class Success<T>(val value: T): NetworkResponse<T>()
data class GenericError(val code: Int? = null, val error: String? = null): NetworkResponse<Nothing>()
object NetworkError: NetworkResponse<Nothing>()
class UnknownError(message: String? = "Unknown Error") : NetworkResponse<Nothing>()
}
如果我删除"out "用"T"接下来的课程开始失败。有人能解释一下为什么我们需要&;out &;(协变)在上面的代码指针,为什么下面的代码失败?
suspend fun <T> call(dispatcher: CoroutineDispatcher, apiCall: suspend () -> Response<T>): NetworkResponse<T> {
return withContext(dispatcher) {
try {
val data = apiCall.invoke()
if (data.isSuccessful) {
data.body()?.let { NetworkResponse.Success(it) } ?: NetworkResponse.UnknownError()
} else {
NetworkResponse.NetworkError
}
} catch (throwable: Throwable) {
when (throwable) {
is IOException -> {
Log.e("IOException", throwable.message?:"")
NetworkResponse.NetworkError
}
is HttpException -> {
Log.e("HttpException", throwable.message?:"")
val code = throwable.code()
val errorResponse = throwable.message()
NetworkResponse.GenericError(code, errorResponse)
}
else -> {
Log.e("GenericException", throwable.message?:"")
NetworkResponse.GenericError(null, null)
}
}
}
}
}
NetworkResponse<Nothing>
是NetworkResponse<out T>
的子类型,而不是NetworkResponse<T>
的子类型。如果你从逻辑上考虑所有的可能性,那就说得通了。
这允许NetworkResponse的错误子类型是单例objects
或更灵活的数据类,不受类型的约束。
例如,NetworkError
没有可以从中检索的T
数据,因此无论T
是什么,它都可以作为NetworkResponse
的子类型,因为无论如何您都不会从中提取T
。因此,NetworkError
的单个实例是任何类型的有效NetworkResponse。
从概念上讲,您可以将Nothing
类型视为所有类型的子类型,就像您可以将Any
类型视为所有类型的超类型一样。