2016-07-07 68 views
6

我在努力了解高阶函数以及如何使用Kotlin将函数作为参数传递给其他函数。我有一个基本的例子,我想fufill: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) 
    } 

我打电话这样上面的方法:

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

我知道:

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

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

回答

2

我觉得混淆来自参数名称,特别是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() 
    } 
} 

不过,我觉得它会更容易执行的代码,如果你想申请以下更改:

  • 使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

+0

非常感谢你,正如用户@voddan指出的那样,你修正了上面的答案,我根本没有使用参数。最后,我遵循你的adivice,并且定义了函数,并在调用中指定了lambda。请你澄清一下,“it”作为参数传递的意思是什么?: –

+1

@EdgarDaSilvaFernandes [另一个有用的约定是,如果一个函数literal只有一个参数,它的声明可以省略(和 - >一起),它的名字将是'it'](https://kotlinlang.org/docs/reference/lambdas.html) – miensol

2

坦白地说,我并不完全相信你的代码是实现,但让我澄清一下您的代码段做什么,至少:

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

+0

我现在明白我的错,那是什么你说,我完全忽略了函数的参数代码背后的想法是高阶函数与更新结果不在一个类中,我想保持这种方式。感谢您的澄清! –

+1

欢迎!看起来你没有阅读文档就做了很高级的东西。我建议您至少从开始到中间阅读网站上的文档。它相当短。 – voddan

+1

你是对的,我对这门语言太兴奋了,并且想尽快开始使用它的功能,但我会再次按照你的建议阅读它。再次感谢! –

0

我通过空的FUNC当我宣布它(因为我需要通过在编译时的东西),但是,呼叫从内部addOnSearchGameResultListener()没有通过运行参数

在运行时或编译时没有通过。如果您使用的功能只有一次像updateSearchResults(null),该if永远是假的,整个事情就相当于{ showNoResultsFoundMessage() }

0

有由胡安·伊格纳西奥·萨拉维亚创建excellent article是谈论高阶函数

我将在这里总结一下:

高阶函数是一个函数,它的参数为 ,或者返回一个函数。

传递函数的参数

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

此功能“logExecution”让你传递一个函数的参数和日志前,这个功能执行后。

FUNC:() - >单位

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

你可以通过必须不能以这种方式接受或返回任何值,就像一个lambda表达式调用这个函数:

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

而且科特林允许你删除括号如果只有一个功能参数,如果最后一个参数是一个函数:

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 
} 

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

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

并以这种方式使用它:

isLollipopOrAbove { 
    // run lollipop specific code safely 
} 

我希望这一点,它已成为一个更清晰一点关于高阶函数