【问题标题】:How Kotlin Higher-Order Functions work?Kotlin 高阶函数如何工作?
【发布时间】:2016-07-07 02:36:51
【问题描述】:

我很难理解高阶函数以及如何使用 Kotlin 将函数作为参数传递给其他函数。我有一个我想完成的基本示例:

fun addOnSearchGameResultListener(
            activity: AppCompatActivity,
            releaseThread: () -> Unit,
            showNoResultsFoundMessage: () -> Unit,
            updateSearchResults: (result: List<Game>) -> Unit) {
        var event0017Handler: TaskExecutor = object : TaskExecutor {
            override fun executeOnSuccessTask(response: JSONObject) {
                async() {
                    uiThread {
                        try {
                            releaseThread()
                            mLoaderManager.hideIndeterminateProgressBar(activity)
                            val result = mJSONParser.getGamesByGameKey(response)
                            Log.i(GameController::class.simpleName, "response: ${result.toString()}")
                            updateSearchResults(result)
                        } catch (e: JSONException) {
                            showNoResultsFoundMessage()
                        }
                    }
                }
            }

            override fun executeOnErrorTask(payload: JSONObject) {
                releaseThread()
                mNotificationManager.showErrorPopUp(activity, payload.getString("data"))
            }
        }
        NotificationCenter.RegistrationCenter.registerForEvent(EventCatalog.e0017, event0017Handler)
    }

我是这样调用上面的方法的:

mGameService.addOnSearchGameResultListener(
            this,
            releaseThread(),
            showNoResultsFoundMessage(),
            updateSearchResults(null)
    )

updateSearchResults(null) 被声明为:

private fun updateSearchResults (results : List<Game>?) : (results : List<Game>?) -> Unit = {
        if (null != results && results.size > 0) {
            mLastMatchingQuery = query_container.text.toString()
            hideNoResultsFoundMessage()
            mGames = results
            mAdapter!!.dataSet = results.toMutableList()
        } else {
            showNoResultsFoundMessage()
        }
    }

我知道我在声明它时将 null 传递给了 func(因为我需要在编译时传递一些东西),但是,从 addOnSearchGameResultListener() 内部进行的调用不是从运行时传递参数的,我的意思是,在addOnSearchGameResultListener() 中,我总是得到 null 的结果。这到底是如何工作的,我做错了什么?

【问题讨论】:

    标签: android kotlin


    【解决方案1】:

    我认为混淆来自参数名称,尤其是results。要解决这个问题,您可以将 updateSearchResults 更改为即:

    private fun updateSearchResults() : (List<Game>?) -> Unit = { results ->
        if (null != results && results.size > 0) {
            mLastMatchingQuery = query_container.text.toString()
            hideNoResultsFoundMessage()
            mGames = results
            mAdapter!!.dataSet = results.toMutableList()
        } else {
            showNoResultsFoundMessage()
        }
    }
    

    但我确实认为,如果您应用以下更改,则更容易遵循代码:

    • 制作updateSearchResults正则方法:

      private fun updateSearchResults (results : List<Game>?) {
          if (null != results && results.size > 0) {
              mLastMatchingQuery = query_container.text.toString()
              hideNoResultsFoundMessage()
              mGames = results
              mAdapter!!.dataSet = results.toMutableList()
          } else {
              showNoResultsFoundMessage()
          }
      }
      
    • 更改 addOnSearchGameResultListener 调用并传递一个 lambda

      mGameService.addOnSearchGameResultListener(
              this,
              releaseThread(),
              showNoResultsFoundMessage(),
              { updateSearchResults(it) }
      )
      
    • releaseThreadshowNoResultsFoundMessage应用类似的更改

    【讨论】:

    【解决方案2】:

    坦率地说,我不完全确定您的代码要实现什么,但让我澄清一下您的 sn-p 至少在做什么:

    private fun updateSearchResults(results : List<Game>?):
             (foo: List<Game>?) -> Unit = { parameter: List<Game>? ->
    
        if (null != results && results.size > 0) {
            // code
            Unit
        } else {
            // code
            Unit
        }
    }
    

    这里有一个函数updateSearchResults,它接受参数results 并返回一个(foo: List&lt;Game&gt;?) -&gt; Unit 类型的函数。请注意,我重命名了一些东西以避免名称冲突并澄清什么是什么。命名foo 没有任何效果,我不知道为什么允许你写它。返回的 lambda 有一个 parameter 类型的 List&lt;Game&gt;? 参数,您在代码中完全忽略了它。总的来说,if 的结果完全取决于updateSearchResults 的参数。

    【讨论】:

    • 我现在明白我的错误了,就是你说的,我完全忽略了函数的参数代码背后的想法是高阶函数与更新在不同的类中结果,我想保持这种状态。感谢您的澄清!
    • 欢迎您!看起来您在不阅读文档的情况下正在做一些非常高级的事情。我建议您至少从头到尾阅读网站上的文档。它相当短。
    • 你说得对,我对这门语言太兴奋了,想尽快开始使用它的功能,但我会按照你的建议再读一遍。再次感谢!
    • 还可以看看 Kotlin Koans。它们是 42 个简短的 kotlin 编码测试,可确保您正确掌握所有内容
    【解决方案3】:

    有一个由 Juan Ignacio Saravia 创建的 excellent article 谈论高阶函数

    我在这里尝试总结一下:

    高阶函数是将函数作为 参数,或者返回一个函数。

    将函数作为参数传递

    fun logExecution(func: () -> Unit) {
        Log.d("tag", "before executing func")
        func()
        Log.d("tag", "after executing func")
    }
    

    此函数“logExecution”允许您将函数作为参数传递并记录该函数执行前后的日志。

    func: ()-> 单位

    这里“func”是参数的名称,“() -> Unit”是参数的“类型”,在这种情况下,我们是说 func 将是一个不接收任何参数且不返回任何值的函数(请记住 Unit 在 Java 中的工作方式类似于 void)。

    您可以通过传递一个不得接收或返回任何值的 lambda 表达式来调用此函数,如下所示:

    logExecution( { Log.d("tag", "I'm a function") } )
    

    如果只有一个函数参数或最后一个参数是函数,Kotlin 还允许您删除括号:

    logExecution { Log.d("tag", "I'm a function") }
    

    接收另一个参数

    我们可以改变 logExecution 签名来接收另一个参数,然后将函数参数放在末尾,如下所示:

    // added tag parameter:
    fun logExecution(tag: String, func: () -> Unit) { ... }
    // call in this way:
    logExecution("tag") { Log.d("tag", "I'm a function") }
    

    或:

    logExecution("tag") {
        Log.d("tag", "I'm a function")
    }
    

    使函数接收和返回值

    fun logExecution(func: (String, String) -> Int) {
        val thisIsAnInt = func("Hello", "World")
    }
    

    异步函数示例

    这是一个接收函数并在另一个线程中执行的函数:

    fun runAsync(func: () -> Unit) {
        Thread(Runnable { func() }).start()
    }
    

    我们可以轻松地在主 UI 线程之外执行一个函数:

    runAsync {
        // i.e.: save something in the Database
    }
    

    也许你想为 Lollipop 设备运行一些特定的代码,而不是做常规的 if 检查,你可以使用这个函数:

    fun isLollipopOrAbove(func: () -> Unit) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            func()
        }
    }
    

    并以这种方式使用它:

    isLollipopOrAbove {
        // run lollipop specific code safely
    }
    

    我希望有了这个,它对高阶函数变得更加清晰了

    【讨论】:

      【解决方案4】:

      我在声明它时将 null 传递给了 func(因为我需要在编译时传递一些东西),但是,从 addOnSearchGameResultListener() 内部进行的调用并未从运行时传递参数

      在运行时或编译时没有传递。如果像updateSearchResults(null)这样只使用一次函数,if总是假的,整个就相当于{ showNoResultsFoundMessage() }

      【讨论】:

        猜你喜欢
        • 2021-05-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-29
        • 2020-03-22
        • 2020-04-04
        • 2018-05-16
        相关资源
        最近更新 更多