Введите безопасное использование общих закрытых классов
Я нашел интересную вещь, когда я пишу общий запечатанный класс. Вот первая версия:
// 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, чтобы представить "значение, которое никогда не существует".
Это также означает, что это подтип всего и, таким образом, также работает для дженериков.