2016-07-07 83 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 
} 

我希望這一點,它已成爲一個更清晰一點關於高階函數