Kotlin - 我如何从我的方法中返回不同的类型?

时间:2017-11-22 21:57:13

标签: generics kotlin

我有这种方法。

    private fun getOffer(offers: OfferRepresentation, type: OfferType): ???? {
    return when (type) {
        OfferType.ADDON -> offers.addon 
        OfferType.SALE -> offers.sale
        OfferType.PLAN -> offers.plan
        OfferType.CUSTOMPLAN -> offers.customPlan
    }

如何更改此方法以返回正确的类型?

4 个答案:

答案 0 :(得分:6)

如果没有提供更多信息,很难给出一个明确的答案,但返回多种类型的最简单方法是让它们共享一个接口或超类:

interface Offer

class Addon : Offer
class Sale : Offer
class Plan : Offer
class CustomPlan : Offer

如果您的选项是静态的,您也可以使用sealed class,这取决于您的使用案例。无论哪种方式,您都可以将函数返回类型设为Offer

有关详细信息,请参阅:

答案 1 :(得分:1)

以下是如何做到这一点:

object Main {

    // concrete class for all "enum" values (such as OfferType.ADDON or OfferType.SALE)
    // that get passed to `getOffer` as second param
    class OfferType<T> {

        companion object Types {

            // "enum" values. Unfortunately Kotlin doesn't support
            // type parameters for real enums
            @JvmStatic
            val ADDON = OfferType<Addon>()

            @JvmStatic
            val SALE = OfferType<Sale>()

            data class Addon(val name: String)
            data class Sale(val name: String)
        }
    }

    data class OfferRepresentation(
        val addon: OfferType.Types.Addon,
        val sale: OfferType.Types.Sale
    )

    @JvmStatic
    fun main(args: Array<String>) {

        fun <T> getOffer(offers: OfferRepresentation, type: OfferType<T>): T {
            @Suppress("UNCHECKED_CAST")
            return when (type) {
                OfferType.ADDON -> offers.addon as T
                OfferType.SALE -> offers.sale as T
                else -> throw IllegalArgumentException("Unsupported type $type")
            }
        }

        val offer = OfferRepresentation(
            OfferType.Types.Addon("addon"),
            OfferType.Types.Sale("sale")
        )

        // types are specified explicitly for the sake of demonstration
        val addon: OfferType.Types.Addon = getOffer(offer, OfferType.ADDON)
        val sale: OfferType.Types.Sale = getOffer(offer, OfferType.SALE)

        println("$addon, $sale")
    }
}

请注意UNCHECKED_CAST函数中有getOffer。您有责任确保使用正确的OfferType.ADDON字段类型参数化OfferType.SALEOfferRepresentation等)值,并且when逻辑也正确,否则您将在运行时获取ClassCast异常。

<强> UPD 即可。有一种替代实现使用了一些kotlin魔法,特别是reified types。使用此方法而不是使用单独的实体来定义要从getOffer函数返回的字段,您只需指定显式类型参数。或者,您可以依赖隐式类型推断:

object Main2 {

    object OfferType {
        data class Addon(val name: String)
        data class Sale(val name: String)
    }

    data class OfferRepresentation(
        val addon: OfferType.Addon,
        val sale: OfferType.Sale
    )

    //reified type parameters require function to be inline
    inline fun <reified T> getOffer(offers: OfferRepresentation): T {
        @Suppress("UNCHECKED_CAST")
        return when (T::class) {
            OfferType.Addon::class -> offers.addon as T
            OfferType.Sale::class -> offers.sale as T
            else -> throw IllegalArgumentException("Unsupported type ${T::class}")
        }
    }

    @JvmStatic
    fun main(args: Array<String>) {

        val offer = OfferRepresentation(
            OfferType.Addon("addon"),
            OfferType.Sale("sale")
        )

        // types needed to be specified explicitly here
        val addon: OfferType.Addon = getOffer(offer)
        val sale: OfferType.Sale = getOffer(offer)

        // alternatively `getOffer` should be invoked like this:
        getOffer<OfferType.Addon>(offer)

        println("$addon, $sale")
    }
}

答案 2 :(得分:1)

您可以使用Any作为返回类型的简单解决方案。 Any与Java中的Object不完全相同,但在这种情况下它足够接近https://kotlinlang.org/docs/reference/classes.html):

  

Kotlin中的所有课程都有一个共同的超类任何,这是默认的   对于没有声明超类型的类的超级:

class Example // Implicitly inherits from Any

因此,如果您的返回类型完全不相关,并且让它们共享一个公共接口没有意义,那么您可以使用Any:

private fun getOffer(offers: OfferRepresentation, type: OfferType): Any {
    return when (type) {
        OfferType.ADDON -> offers.addon 
        OfferType.SALE -> offers.sale
        OfferType.PLAN -> offers.plan
        OfferType.CUSTOMPLAN -> offers.customPlan
    }

答案 3 :(得分:-1)

您不能通过JVM从函数返回多于1个值。 你可以做的是返回一个Pair或Tuple或创建一个包含所有字段的Data类,然后将它们作为可选项

例如:

数据类Offer(val type1:String?= null,val type2:Integer?= 0)