Ошибка компиляции типа Kotlin: требуется Success <T>, Found MyError

Я столкнулся с проблемой, что следующий код не может быть скомпилирован в kotlin.

// StateModel.kt sealed class StateModel class Loading : StateModel() data class Success<T: Any>(val data: T) : StateModel() data class MyError(val message: String) : StateModel() // StateModelTransformer.kt class StateModelTransformer<T: Any> : FlowableTransformer<T, StateModel> { override fun apply(upstream: Flowable<T>): Publisher<StateModel> { return upstream .map { data -> Success(data) } .onErrorReturn { error -> MyError(error.message) // compile error, Type mismatch, Require Success<T>, Found MyError } .startWith(Loading()) // compile error, none of the following function can be called with the arguments supplied } } 

Я понятия не имею, почему onErrorReturn говорит, что требуется тип Success<T> но тип StateModel .

благодаря

Ниже приведены соответствующие декларации в Flowable для справки. Не будем игнорировать onErrorReturn ; это не относится к проблеме здесь.

 public Flowable<T> { public <R> Flowable<R> map(Function<? super T, ? extends R> mapper); public Flowable<T> startWith(T value); } 

Это типы Котлин.

 val upstream: Flowable<T> val mapper: (T) -> Success<T> = { data -> Success(data) } val map: ((T) -> Success<T>) -> Flowable<Success<T>> = upstream::map val mapped: Flowable<Success<T>> = map(mapper) val loading: Loading = Loading() val startWith: (Success<T>) -> Flowable<Success<T>> = mapped::startWith startWith(loading) // type mismatch 

Более конкретный тип Success<T> уже был выведен ранее, и Котлин не отступает, чтобы найти более общий тип StateModel . Чтобы заставить это произойти, вы можете вручную указать типы, например

 // be explicit about the general type of the mapper upstream.map { data -> Success(data) as StateModel }.startWith(Loading()) // be explicit about the generic type R = StateModel upstream.map<StateModel> { data -> Success(data) }.startWith(Loading()) 

Кстати, вы теряете <T> в StateModel . Я бы предложил изменить базовый класс, чтобы включить параметр типа.

 sealed class StateModel<out T: Any> object Loading : StateModel<Nothing>() data class Success<T: Any>(val data: T) : StateModel<T>() data class MyError(val message: String) : StateModel<Nothing>() 

Это позволит вам написать, например,

 val <T: Any> StateModel<T>.data: T? get() = when (this) { is Success -> data else -> null }