在Kotlin中返回不同类型的Object

时间:2019-01-11 20:41:43

标签: object kotlin return

我正在使用一种返回不同类型对象的方法,我使用了Any type return,但是有更好的选择来实现这一点吗? 这是我的方法:

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 :(得分:2)

您需要的是co-product类型,就像许多流行的FP库中的Either数据类型一样,对于Kotlin,Arrow-kt已经provide it,但是可以做得到也使用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)

答案 1 :(得分:0)

科特琳介绍Sealed classes,这正是您在这里需要的。在您的示例中,它可能看起来像这样:

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
            }
        }
    }
}

从功能编程语言中将may be used密封的类Algebraic Data Types密封为https://jsfiddle.net/3p5ge0h9/。我主要将它们用作枚举,用于模型类型(ChatTypeConnectionStatus),视图状态和网络请求结果。

答案 2 :(得分:0)

您可以考虑使函数通用,如下所示:

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

但是对于您的用例而言,这没有什么不同。正确使用方法来区分不同类型是正确的方法,因为item将被适当地智能广播以备将来使用。