【问题标题】:A function with generic return type具有通用返回类型的函数
【发布时间】:2017-05-15 15:00:42
【问题描述】:

是否可以有一个返回泛型类型的函数?比如:

fun <T> doSomething() : T {
    when {
        T is Boolean -> somethingThatReturnsBoolean()
        T is Int -> somethingThatReturnsInt()
        else -> throw Exception("Unhandled return type")
    }
}

【问题讨论】:

    标签: generics kotlin


    【解决方案1】:

    您可以使用具体类型来捕获其类字面量,如下所示:

    inline fun <reified T> doSomething() : T {
        return when (T::class.java) {
            Boolean::class.java -> somethingThatReturnsBoolean() as T
            Int::class.java -> somethingThatReturnsInt() as T
            else -> throw Exception("Unhandled return type")
        }
    }
    

    但您还必须让编译器相信 T 是 Boolean 或 T 是 Int,如示例所示,使用未经检查的强制转换。

    reified 使真正的 T 的类型可访问,但仅适用于内联函数。如果你想要一个常规的函数,你可以试试:

    inline fun <reified T> doSomething() : T = doSomething(T::class.java)
    fun <T> doSomething(klass: Class<T>): T {
        return when (klass) { ... }
    }
    

    【讨论】:

    • 但函数没有返回,如果返回布尔或整数作为返回类型,会出现编译问题
    • 谢谢@zt1983811,我已经添加了return声明。
    • 我怎样才能调用这个布尔方法?
    【解决方案2】:

    Any 可能是您想要使用的东西。它是 Kotlin 类层次结构的根。

    对于语法为Any? 的 Any 也是可选的

    fun doSomething(key: Any): Any {
        when {
                 key is Boolean -> return true
                 key is Int -> return 1
                 else -> throw Exception("Unhandled return type")
             }
    }
    

    【讨论】:

      【解决方案3】:

      您还可以将somethingThatReturnsInt() 等函数直接传递给泛型函数,并从传递的函数本身推断返回类型。这是Kotlin 的示例:

      // This function takes any method you provide and infers the result-type
      public fun<T> generic_function(passed_function: () -> T): T? =
          passed_function()
      
      
      // Pass your function. The return type will be inferred directly from somethingThatReturnsInt()'s return-type
      val res: Int? = generic_function(::somethingThatReturnsInt)
      
      // For the sake of completeness, this is valid as well
      val res: Int? = generic_function<Int?> { somethingThatReturnsInt() }
      

      这样您就不必处理when-scenarios 并且您的返回类型是通用的,具体取决于传递的函数。

      【讨论】:

        【解决方案4】:

        好吧,有一种方法可以做这样的事情,但感觉有点 hacky:

        data class Coffee(val milk: Double, val sugar: Int)
        
        class ComparingBuilder(val oldInstance: Coffee, val updatedInstance: Coffee) {
             operator fun <T> invoke(accessor: Coffee.() -> T?): T? =
                 if (whatever) { oldInstance.accessor() }
                 else { updatedSupplier.accessor() }
        }
        
        fun useComparingBuilder(
            oldInstance: Coffee,
            updatedInstance: Coffee,
        ) = OptionalBuilder(oldInstance, updatedInstance).let { builder ->
            val remixedCoffee = Coffee(
                milk = builder { milk },
                sugar = builder { sugar },
            )
        }
        

        所以,简而言之,不,这不是一种制作通用 lambda 的方法 - 但它是一种制作可以像使用通用 lambda 一样使用的东西的方法。

        难以用语言表达;我希望代码更清晰....

        【讨论】:

          猜你喜欢
          • 2015-12-28
          • 2012-08-18
          • 1970-01-01
          • 1970-01-01
          • 2020-05-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多