我正在努力理解高阶函数以及如何使用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的结果。这究竟是如何运作的,我做错了什么?
答案 0 :(得分:2)
坦率地说,我不完全确定你的代码是什么,但让我澄清你的代码片段至少在做什么:
A
这里有一个函数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有一个foo
类型的parameter
参数,您可以在代码中完全忽略它。总而言之,List<Game>?
的结果完全取决于if
的参数。
答案 1 :(得分:2)
我认为混淆来自参数名称,特别是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()
}
}
但是,如果您应用以下更改,我觉得更容易遵循代码:
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) }
)
对releaseThread
,showNoResultsFoundMessage
答案 2 :(得分:0)
当我声明它时,我将null传递给func(因为我需要在编译时传递一些东西),但是,从addOnSearchGameResultListener()内部调用不会从运行时传递参数
在运行时或编译时没有传递。如果您仅使用updateSearchResults(null)
一次的函数,则if
始终为false,整个事件等同于{ showNoResultsFoundMessage() }
答案 3 :(得分:0)
Juan Ignacio Saravia创建了excellent article,讨论高阶函数
我将尝试总结一下:
高阶函数是一个函数,它将函数作为 参数,或返回一个函数。
将函数作为参数传递
fun logExecution(func: () -> Unit) {
Log.d("tag", "before executing func")
func()
Log.d("tag", "after executing func")
}
此函数“logExecution”允许您在执行此函数之前和之后传递函数作为参数和日志。
func :() - &gt;单元强>
此处“func”是参数的名称,“() - &gt;单位“是参数的”类型“,在这种情况下,我们说func将是一个不接收任何参数并且不返回任何值的函数(请记住,单位的工作方式类似于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 check,你可以使用这个函数:
fun isLollipopOrAbove(func: () -> Unit) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
func()
}
}
并以这种方式使用它:
isLollipopOrAbove {
// run lollipop specific code safely
}
我希望有了它,它对高阶函数有了更清晰的认识