【问题标题】:Kotlin - How can i return different types from my method?Kotlin - 我如何从我的方法中返回不同的类型?
【发布时间】:2020-08-13 17:54:59
【问题描述】:

我有这个方法。

    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
    }

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

【问题讨论】:

  • OfferRepresentation 类是什么样的?
  • @fejd OfferRepresentation 有四个属性 (offerTypes),可以是 addon、sale、plan 或 customPlan。如果 OfferRepresentation 有计划(或任何其他),则其他属性为空。

标签: generics kotlin


【解决方案1】:

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

interface Offer

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

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

欲了解更多信息,请参阅:

【讨论】:

  • 如果你不能控制课程,你会怎么做?例如。 String、Int 或 Float
  • @CLOVIS 如果你真的要返回anything,你可以使用Any作为返回类型。
【解决方案2】:

您有一个简单的解决方案,即使用Any 作为您的返回类型。 Any 与 Java 中的 Object 不完全一样,但在这种情况下已经足够接近了 (https://kotlinlang.org/docs/reference/classes.html):

Kotlin 中的所有类都有一个共同的超类 Any,这是默认的 super 用于没有声明超类型的类:

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
    }

【讨论】:

  • 如果您希望能够返回AnyAny?,Kt 编译器会以不同方式处理它们
  • @kzs 在这种情况下你可以返回Any?
【解决方案3】:

您可以这样做:

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

请注意,getOffer 函数中有一个 UNCHECKED_CAST。您有责任确保 OfferType.ADDONOfferType.SALE 等)值使用正确的 OfferRepresentation 字段类型进行参数化,并且 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")
    }
}

【讨论】:

    【解决方案4】:

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

    例如:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-06
      • 1970-01-01
      • 1970-01-01
      • 2022-11-15
      • 1970-01-01
      相关资源
      最近更新 更多