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
调用并传递一个lambdamGameService.addOnSearchGameResultListener( this, releaseThread(), showNoResultsFoundMessage(), { updateSearchResults(it) } )
-
对
releaseThread
,showNoResultsFoundMessage
应用类似的更改
坦率地说,我不完全确定你的代码是要实现的,但是让我澄清一下你的代码片段至少在做什么:
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 }
我希望借此,高阶函数变得更清晰一些