2016-07-07 19 views
6

Tôi đang đấu tranh một chút để hiểu các hàm bậc cao và cách chuyển các hàm thành các tham số cho các hàm khác bằng Kotlin. Tôi có một ví dụ cơ bản mà tôi muốn fufill:Chức năng đặt hàng của Kotlin cao hơn hoạt động như thế nào?

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

Tôi kêu gọi các phương pháp trên theo cách này:

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

updateSearchResults(null) được khai báo là:

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

tôi biết Tôi đã chuyển null thành func khi tôi khai báo nó (vì tôi cần truyền một thứ gì đó ở thời gian biên dịch), tuy nhiên, cuộc gọi được thực hiện từ bên trong addOnSearchGameResultListener() không được thực hiện thông qua tham số từ thời gian chạy, Ý tôi là, trong addOnSearchGameResultListener() Tôi luôn nhận được kết quả vô giá trị. Làm thế nào chính xác điều này hoạt động và những gì tôi làm sai?

Trả lời

2

Tôi nghĩ sự nhầm lẫn xuất phát từ tên thông số, cụ thể là results. Để giải quyết mà bạn có thể thay đổi updateSearchResults để tức là:

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

Tuy nhiên tôi cảm thấy rằng nó sẽ dễ dàng hơn để làm theo các mã nếu bạn muốn áp dụng những thay đổi sau đây:

  • làm updateSearchResults phương pháp thông thường:

    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() 
        } 
    } 
    
  • thay đổi các addOnSearchGameResultListener gọi và vượt qua một lambda

    mGameService.addOnSearchGameResultListener(
         this, 
         releaseThread(), 
         showNoResultsFoundMessage(), 
         { updateSearchResults(it) } 
    ) 
    
  • áp dụng thay đổi tương tự như releaseThread, showNoResultsFoundMessage

+0

Cảm ơn bạn rất nhiều, vì người dùng @voddan đã chỉ ra và bạn sửa chữa câu trả lời ở trên, tôi không sử dụng tham số nào cả. Cuối cùng, tôi đã theo dõi ý tưởng của bạn và thực hiện các chức năng thường xuyên và chỉ định lambda trong cuộc gọi. Bạn có thể vui lòng làm rõ cho tôi biết chính xác "nó" được truyền như tham số nghĩa là gì không ?: –

+1

@EdgarDaSilvaFernandes [Một quy ước hữu ích khác là nếu một hàm chỉ có một tham số, khai báo của nó có thể bị bỏ qua (cùng với ->), và tên của nó sẽ là 'it'] (https://kotlinlang.org/docs/reference/lambdas.html) – miensol

2

Thẳng thắn mà nói, tôi không hoàn toàn chắc chắn những gì mã của bạn là để đạt được, nhưng hãy để tôi làm rõ những gì đoạn mã của bạn đang làm ít nhất:

private fun updateSearchResults(results : List<Game>?): 
     (foo: List<Game>?) -> Unit = { parameter: List<Game>? -> 

    if (null != results && results.size > 0) { 
     // code 
     Unit 
    } else { 
     // code 
     Unit 
    } 
} 

Ở đây bạn có một hàm updateSearchResults mà chấp nhận một tham số results và trả về một hàm thuộc loại (foo: List<Game>?) -> Unit. Lưu ý rằng tôi đã đổi tên một số thứ để tránh xung đột tên và làm rõ những gì là gì. Việc đặt tên foo không có tác dụng gì cho đến giờ, tôi không chắc tại sao bạn được phép viết nó. Lambda trở về có một tham số parameter thuộc loại List<Game>?, mà bạn hoàn toàn bỏ qua trong mã của mình. Hơn hết, kết quả của if phụ thuộc hoàn toàn vào tham số của updateSearchResults.

+0

tôi đã hiểu sai lầm của tôi bây giờ, nó là những gì bạn đã nói, tôi hoàn toàn bỏ qua tham số của hàm Ý tưởng đằng sau mã là hàm bậc cao nằm trong một lớp khác với kết quả cập nhật và tôi muốn giữ nó theo cách đó. Cảm ơn bạn đã làm rõ! –

+1

Chào mừng bạn! Có vẻ như bạn đang làm những thứ khá tiên tiến mà không cần đọc tài liệu. Tôi khuyên bạn nên đọc các tài liệu trên trang web từ đầu đến giữa ít nhất. Nó khá ngắn. – voddan

+1

Bạn nói đúng, tôi đã quá hào hứng về ngôn ngữ và muốn bắt đầu sử dụng các tính năng của nó càng sớm càng tốt, nhưng tôi sẽ đọc lại nó khi bạn đã tư vấn. Cảm ơn một lần nữa! –

0

tôi qua null để Func khi tôi tuyên bố nó (vì tôi cần phải vượt qua một cái gì đó vào thời điểm biên soạn), tuy nhiên, cuộc gọi được tạo từ bên trong addOnSearchGameResultListener() không được chuyển thông số từ thời gian chạy

Không có thời gian chạy hoặc thời gian biên dịch.Nếu bạn sử dụng chức năng chỉ một lần như updateSearchResults(null), các if luôn là sai, và toàn bộ điều là tương đương với { showNoResultsFoundMessage() }

0

Có một excellent article tạo ra bởi Juan Ignacio Saravia rằng nói về bậc cao Chức năng

Tôi sẽ cố tóm tắt tại đây:

Hàm bậc cao hơn là hàm có chức năng như thông số hoặc trả về hàm.

Vượt qua một chức năng như tham số

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

Chức năng này “logExecution” cho phép bạn vượt qua một chức năng như tham số và đăng nhập trước và sau khi thực hiện chức năng này.

func:() -> Đơn vị

Đây “Func” là tên của tham số và “() -> Unit” là “loại” của tham số, trong này trường hợp, chúng tôi đang nói rằng func sẽ là một chức năng mà không nhận được bất kỳ tham số và không trả lại bất kỳ giá trị (hãy nhớ rằng đơn vị hoạt động như void trong Java).

Bạn có thể gọi chức năng này bằng cách thông qua một biểu thức lambda mà không phải nhận hoặc trả lại bất kỳ giá trị, như theo cách này:

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

mà còn Kotlin cho phép bạn loại bỏ các dấu ngoặc đơn nếu chỉ có một chức năng tham số hoặc nếu tham số cuối cùng là một chức năng:

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

Nhận thông số khác

Chúng tôi có thể thay đổi chữ ký logExecution để nhận thông số khác và sau đó đặt các tham số chức năng ở phần cuối như thế này:

// added tag parameter: 
fun logExecution(tag: String, func:() -> Unit) { ... } 
// call in this way: 
logExecution("tag") { Log.d("tag", "I'm a function") } 

hay:

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

Tận dụng chức năng tiếp nhận và trả lại giá trị

fun logExecution(func: (String, String) -> Int) { 
    val thisIsAnInt = func("Hello", "World") 
} 

Ví dụ về chức năng không đồng bộ

Đây là một chức năng tiếp nhận một chức năng và thực hiện nó trong một thread:

fun runAsync(func:() -> Unit) { 
    Thread(Runnable { func() }).start() 
} 

và chúng tôi có thể thực hiện một chức năng bên ngoài của Chính UI Chủ đề một cách dễ dàng:

runAsync { 
    // i.e.: save something in the Database 
} 

Có lẽ bạn muốn để chạy một số mã cụ thể cho các thiết bị Lollipop và thay vì thực hiện kiểm tra định kỳ, bạn có thể sử dụng chức năng này:

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

và sử dụng nó theo cách này:

isLollipopOrAbove { 
    // run lollipop specific code safely 
} 

Tôi hy vọng với điều này, nó đã trở thành rõ ràng hơn một chút về hàm bậc cao

Các vấn đề liên quan