Kotlin高阶函数如何工作?

为了理解高阶函数以及如何将函数作为参数传递给使用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()我总是得到空的结果。 这是如何工作,我做错了什么?

我认为混淆来自参数名称,特别是results 。 要解决这个问题,你可以把updateSearchResults改成ie:

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

不过,我认为,如果您应用以下更改,则可以更轻松地执行代码:

  • make 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应用类似的更改

坦率地说,我不完全确定你的代码是要实现的,但是让我澄清一下你的代码片段至少在做什么:

 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<Game>?) -> Unit的函数。 请注意,我重命名了一些事情,以避免名称冲突,并澄清什么是什么。 这个命名没有任何效果,我不知道为什么你可以写它。 返回的lambda具有List<Game>?类型的一个参数parameter List<Game>? ,你完全忽略了你的代码。 总而言之, if的结果完全取决于updateSearchResults的参数。

当我声明它时(因为我需要在编译时传递一些东西),我将null传递给func,但是,从addOnSearchGameResultListener()内部调用不会传递参数

在运行时或编译时没有通过。 如果只使用一次函数updateSearchResults(null) ,那么if总是为false,整个事物相当于{ showNoResultsFoundMessage() }

胡安·伊格纳西奥·萨拉维亚(Juan Ignacio Saravia)创造了一篇很棒的文章 ,谈论高阶函数

我会在这里总结一下:

高阶函数是以函数作为参数或返回函数的函数。

传递一个函数作为参数

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

这个函数“logExecution”允许你在这个函数执行之前和之后传递一个函数作为参数和日志。

func:() – > Unit

这里“func”是参数的名称, “() – > Unit”是参数的“类型”,在这种情况下,我们说func是一个函数,它不接受任何参数, t返回任何值(记住单元在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 { // ie: save something in the Database } 

也许你想运行一些特定的棒棒糖设备的代码,而不是做常规的检查,你可以使用这个功能:

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

并以这种方式使用它:

 isLollipopOrAbove { // run lollipop specific code safely } 

我希望借此,高阶函数变得更清晰一些