Вернуть разные типы объектов в котлин - PullRequest
0 голосов
/ 11 января 2019

Я работаю с методом, который возвращает различные типы объектов, я использовал возвращаемый тип Any, но есть ли лучший вариант для достижения этой цели? Это мой метод:

override fun getNavItemById(dCSServiceContext: DCSServiceContext): Observable<Any> {
        return scribeProvider.getNavItemById(dCSServiceContext).map { navItem ->
            scribePresenter.presentNativeItem(navItem)
        }.toObservable()
    }

После того, как я выполняю приведение возвращенного объекта с помощью оператора when, я делаю что-то вроде этого:

 when (item) {
                            is NavItem -> {
                                if (parentItem.hasChildren) {
                                    parentItem.items?.add(item)
                                    recursiveItem = item
                                }
                            }
                            is Image -> {
                                if (parentItem.hasImages) {
                                    parentItem.image = Image(item.image, item.selectedImage)
                                    recursiveItem = parentItem
                                }
                            }
                        }

И другое мое сомнение в том, как я могу использовать этот метод и извлекать этот тип объекта другим способом.

Спасибо !!!

Ответы [ 3 ]

0 голосов
/ 12 января 2019

Kotlin представляет Запечатанные классы , что именно то, что вам нужно здесь. В вашем примере это может выглядеть так:

sealed class NavItem {
    object Item : NavItem()
    data class Image(val image: String, val selectedImage: String) : NavItem()
}

...

override fun getNavItemById(dCSServiceContext: DCSServiceContext): Observable<NavItem> { ... }

...

// I don't know what class declares getNavItemById function
navigation.getNavItemById(serviceContext).subscribe { item ->
    when (item) {
        is Item -> {
            if (parentItem.hasChildren) {
                parentItem.items?.add(item)
                recursiveItem = item
            }
        }
        is Image -> {
            if (parentItem.hasImages) {
                parentItem.image = Image(item.image, item.selectedImage)
                recursiveItem = parentItem
            }
        }
    }
}

Запечатанные классы могут использоваться (в некоторой степени) как Алгебраические типы данных из функциональных языков программирования. Я в основном использую их как перечисления, для типов моделей (ChatType, ConnectionStatus), состояний просмотра и результатов сетевых запросов.

0 голосов
/ 12 января 2019

Вы можете подумать о том, чтобы сделать вашу функцию общей:

override fun <T: Any> getNavItemById(dCSServiceContext: DCSServiceContext): Observable<T> {
    return scribeProvider.getNavItemById(dCSServiceContext).map { navItem ->
            scribePresenter.presentNativeItem(navItem)
    }.toObservable()
}

но для вашего случая использования это не будет иметь значения. Использование различий между различными типами - правильный путь, поскольку item будет соответствующим образом преобразован для дальнейшего использования.

0 голосов
/ 12 января 2019

Вам нужен тип co-product , такой как тип данных Either, который можно найти во многих популярных библиотеках FP, для Kotlin Arrow-kt уже предоставляет его , но то же самое можно сделать, используя sealed classes.

Пример (закрытый класс )

sealed class Result {
    data class A(val value: Int) : Result()
    data class B(val value: String) : Result()
}

fun intOrString(number: Int): Result =
    if (number%2 == 0) Result.A(number)
    else Result.B("~$number~")

fun main(args: Array<String>) {
    (1..10).map(::intOrString).forEach(::println)
}

выход

B(value=~1~)
A(value=2)
B(value=~3~)
A(value=4)
B(value=~5~)
A(value=6)
B(value=~7~)
A(value=8)
B(value=~9~)
A(value=10)

Пример (любой тип данных)

fun intOrString(number: Int): Either<Int, String> =
    if (number%2 == 0) Left(number)
    else Right("~$number~")

fun main(args: Array<String>) {
    (1..10).map(::intOrString).forEach(::println)
}

выход

Right(b=~1~)
Left(a=2)
Right(b=~3~)
Left(a=4)
Right(b=~5~)
Left(a=6)
Right(b=~7~)
Left(a=8)
Right(b=~9~)
Left(a=10)
...