Введите безопасное использование общих закрытых классов

Я нашел интересную вещь, когда я пишу общий запечатанный класс. Вот первая версия:

// sample interface and implementation
interface MyInterface
class MyInterfaceImpl : MyInterface

sealed class Response<T: MyInterface>               

data class Success<T: MyInterface>(val payload: T) : Response<T>()
data class Failure(val errorCode: Int) : Response<MyInterface>()
object Cancelled : Response<MyInterface>()

скажем, у нас также есть функция запроса, как это:

fun <T: MyInterface> requestObject(cls : KClass<T>): Response<T> = TODO("Request")

Теперь на стороне использования у нас есть ошибки:

fun test() = when (val response = requestObject(MyInterfaceImpl::class)) {
    is Success -> print("Payload is ${response.payload}")     // Smart cast perfectly works!
    is Failure -> print("Error code ${response.errorCode}")   // Incomparable types: Failure and Response<MyInterfaceImpl>
    Cancelled -> print("Request cancelled")                   // Incomparable types: Cancelled and Response<MyInterfaceImpl>
}

Первый вопрос: Failure а также Cancelled не использовать T для позиций входа / выхода, почему этот бросок не проверен, и мне нужно подавить его?

Через некоторое время ConstOrVar показал мне решение, как объявить безопасный тип закрытого класса:

sealed class Response<out T: MyInterface>                    // <-- out modifier here

data class Success<T: MyInterface>(val payload: T) : Response<T>()
data class Failure(val errorCode: Int) : Response<Nothing>() // <-- Nothing as type argument
object Cancelled : Response<Nothing>()                       // <-- Nothing as type argument

Эта декларация работает как шарм, и теперь у меня есть вопросы:

Второй вопрос: зачем писать out модификатор здесь?

Третий вопрос: почему Producer<Nothing> это подтип Producer<MyInterface>? По определению коварианта: Producer<A> это подтип Producer<B> если A подтип B, но Nothing не подтип MyInterface, Похоже на недокументированную экстралингвистическую особенность.

1 ответ

Разница не работает в конце. Response<MyInterfaceImpl> не является Response<MyInterface> и поэтому Failure а также Cancelled не может быть использован. Даже если вы не используете гернерский тип, вы все равно объявляете это.

При сдаче out T, вы будете иметь эффект, как ? extends T на Яве.

Тогда для Nothing у тебя есть:

Ничто не имеет никаких примеров. Вы можете использовать Nothing, чтобы представить "значение, которое никогда не существует".

Это также означает, что это подтип всего и, таким образом, также работает для дженериков.

Другие вопросы по тегам