主頁 > 後端開發 > Kotlin難點

Kotlin難點

2023-05-26 08:16:54 後端開發

目錄
  • 高階函式
  • 雙冒號
    • 函式參考
    • 類參考
    • 屬性參考
  • 匿名函式
  • Lambda 運算式
    • 例子
  • 作用域函式

高階函式

高階函式是將函式用作引數或回傳值的函式,還可以把函式賦值給一個變數,

所有函式型別都有一個圓括號括起來的引數型別串列以及一個回傳型別:(A, B) -> C 表示接受型別分別為 A 與 B 兩個引數并回傳一個 C 型別值的函式型別, 引數型別串列可以為空,如 () -> A,Unit 回傳型別不可省略,

(Int) -> String

函式型別表示法可以選擇性地包含函式的引數名:(x: Int, y: Int) -> Point, 這些名稱可用于表明引數的含義,
(Button, ClickEvent) -> Unit
如需將函式型別指定為可空,請使用圓括號:((Int, Int) -> Int)?

    fun a(funParam: (Int) -> String): String {
        return funParam(1)
    }

    fun b(param: Int): String {
        return param.toString()
    }

呼叫

a(::b)
var d = ::b
b(1) // 呼叫函式
d(1) // 實際上會呼叫 d.invoke(1)
(::b)(1) // 用物件 :: b 后面加上括號來實作 b() 的等價操作, 實際上會呼叫 (::b).invoke(1)
b.invoke(1) // 報錯

物件是不能加個括號來呼叫的,但是函式型別的物件可以,為什么?因為這其實是個假的呼叫,它是 Kotlin 的語法糖,實際上你對一個函式型別的物件加括號、加引數,它真正呼叫的是這個物件的 invoke() 函式

雙冒號

:: 創建一個函式參考或者一個類參考

函式參考

fun isOdd(x: Int) = x % 2 != 0

我們可以很容易地直接呼叫它(isOdd(5)),但是我們也可以將其作為一個函式型別的值,例如將其傳給另一個函式,為此,我們使用 :: 運算子:

val numbers = listOf(1, 2, 3)
println(numbers.filter(::isOdd))

這里 ::isOdd 是函式型別 (Int) -> Boolean 的一個值,

如果我們需要使用類的成員函式或擴展函式,它需要是限定的,例如 String::toCharArray,

    val args: Array<String> = arrayOf("1", "2")
  args.filter(String::isNotEmpty) 
  
  class PdfPrinter {
        fun println(any: Any) {
            kotlin.io.println(any)  //重名了可以用包名呼叫
        }
    }
      val pdfPrinter = PdfPrinter()
      args.forEach(pdfPrinter::println)

類參考

val c = MyClass::class

該參考是 KClass 型別的值
請注意,Kotlin 類參考與 Java 類參考不同,要獲得 Java 類參考, 請在 KClass 實體上使用 .java 屬性,
平時寫的類,其資訊都可以在這個KClass來獲取

屬性參考

data class MediaItem(val title: String, val url: String)

var items= mutableListOf<MediaItem>()
items
    .sortedBy { it.title }
    .map { it.url }
    .forEach { print(it) }

items
    .sortedBy(MediaItem::title)
    .map(MediaItem::url)
    .forEach(::println)

匿名函式

沒有名字的函式
要傳一個函式型別的引數,或者把一個函式型別的物件賦值給變數,除了用雙冒號來拿現成的函式使用,你還可以直接把這個函式挪過來寫:

fun b(param: Int): String {
    return param.toString()
}

a(fun b(param: Int): String {
  return param.toString()
});

val d = fun b(param: Int): String {
  return param.toString()
}

//名字沒意義,省略
a(fun(param: Int): String {
  return param.toString()
});
val d = fun(param: Int): String {
  return param.toString()
}

如果你在 Java 里設計一個回呼的時候是這么設計的:

public interface OnClickListener {
  void onClick(View v);
}
public void setOnClickListener(OnClickListener listener) {
  this.listener = listener;
}

使用的時候是這么用的:

view.setOnClickListener(new OnClickListener() {
  @Override
  void onClick(View v) {
    switchToNextPage();
  }
});

kotlin寫法

fun setOnClickListener(onClick: (View) -> Unit) {
  this.onClick = onClick
}
view.setOnClickListener(fun(v: View): Unit) {
  switchToNextPage()
})

Lambda寫法:

view.setOnClickListener({ v: View ->
  switchToNextPage()
})

Lambda 運算式

簡化匿名函式,代碼更簡潔

    view.setOnClickListener({ v: View ->
        switchToNextPage()
    })

//如果 Lambda 是函式的最后一個引數,你可以把 Lambda 寫在括號的外面:
    view.setOnClickListener() { v: View ->
        switchToNextPage()
    }
//而如果 Lambda 是函式唯一的引數,你還可以直接把括號去了:
    view.setOnClickListener { v: View ->
        switchToNextPage()
    }
//另外,如果這個 Lambda 是單引數的,它的這個引數也省略掉不寫:
//根據背景關系推導,根據最后一行代碼來推斷出回傳值型別
    view.setOnClickListener {
        switchToNextPage()
    }

Lambda 運算式的完整語法形式如下:

val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }
val sum = { x: Int, y: Int -> x + y }

多引數例子:
fold函式:將所提供的操作應用于集合元素并回傳累積的結果

val items = listOf(1, 2, 3, 4, 5)

// Lambdas 運算式是花括號括起來的代碼塊,
items.fold(0, { 
    // 如果一個 lambda 運算式有引數,前面是引數,后跟“->”
    acc: Int, i: Int -> 
    print("acc = $acc, i = $i, ") 
    val result = acc + i
    println("result = $result")
    // lambda 運算式中的最后一個運算式是回傳值:
    result
})

// lambda 運算式的引數型別是可選的,如果能夠推斷出來的話:
val joinedToString = items.fold("Elements:", { acc, i -> acc + " " + i })

輸出:

acc = 0, i = 1, result = 1
acc = 1, i = 2, result = 3
acc = 3, i = 3, result = 6
acc = 6, i = 4, result = 10
acc = 10, i = 5, result = 15
joinedToString = Elements: 1 2 3 4 5

總結:
函式不能直接傳遞或者賦給某個變數,需要函式型別實體化,有三種方式:

使用已有宣告的可呼叫參考
1.函式參考

使用函式字面值的代碼塊

2.匿名函式
3.lambda 運算式

例子

實作介面

var onVideoStartCallBack: (() -> Unit)? = null

onVideoStartCallBack?.invoke()

videioView.onVideoStartCallBack = {

}

函式里實作介面

object UploaderListHelper {

    fun startTaskUpload(activity: Activity, startCallBack: ((Int) -> Unit)?) {
        startCallBack.invoke(position)
    }
}

UploaderListHelper.startTaskUpload(activity) {
    refreshProgress(it)
}

作用域函式

Kotlin 標準庫包含幾個函式,它們的唯一目的是在物件的背景關系中執行代碼塊,當對一個物件呼叫這樣的函式并提供一個 lambda 運算式時,它會形成一個臨時作用域,在此作用域中,可以訪問該物件而無需其名稱,這些函式稱為作用域函式,共有以下五種:let、run、with、apply 以及 also,

這些函式基本上做了同樣的事情:在一個物件上執行一個代碼塊,不同的是這個物件在塊中如何使用,以及整個運算式的結果是什么,
目的:簡潔

 val person = findPerson();
        //person是可null的,所以需要?
        println(person?.age)
        println(person?.name)
        //上面太麻煩,findPerson加了?,所以后面不需要了,減少的判空操作,let可以安全呼叫
        findPerson()?.let { person ->
            person.work()
            println(person.age)
        }
        //還可以更簡潔,person也不用寫
        findPerson()?.apply {
            work()
            println(age)
        }

使?時可以通過簡單的規則作出一些判斷
回傳自身
回傳值是它本身
從 apply 和 also 中選
作?域中使? this 作為引數選擇 apply

val adam = Person("Adam").apply {
    age = 32
    city = "London"        
}
println(adam)

作?域中使? it 作為引數選擇 also

val numbers = mutableListOf("one", "two", "three")
numbers
    .also { println("The list elements before adding new one: $it") }
    .add("four")

with 非擴展函式

val numbers = mutableListOf("one", "two", "three")
with(numbers) {
    println("'with' is called with argument $this")
    println("It contains $size elements")
}

不需要回傳自身
從 run 和 let 中選擇
作用域中使用 this 作為引數,選擇 run
作用域中使用 it 作為引數,選擇 let, 適合配合空判斷的時候

val service = MultiportService("https://example.kotlinlang.org", 80)

val result = service.run {
    port = 8080
    query(prepareRequest() + " to port $port")
}

// 同樣的代碼如果用 let() 函式來寫:
val letResult = service.let {
    it.port = 8080
    it.query(it.prepareRequest() + " to port ${it.port}")
}

it作為引數的好處
let 允許我們自定義引數名字,使可讀性更強,如果傾向可讀性可以選擇 T.let

參考文章
Kotlin 的高階函式、匿名函式和 Lambda 運算式
Kotlin官網

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/553413.html

標籤:其他

上一篇:詳細解讀Java中Map集合的底層原理(干貨+原始碼解讀)

下一篇:返回列表

標籤雲
其他(159701) Python(38169) JavaScript(25452) Java(18129) C(15231) 區塊鏈(8268) C#(7972) AI(7469) 爪哇(7425) MySQL(7211) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5873) 数组(5741) R(5409) Linux(5341) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4576) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2434) ASP.NET(2403) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1976) 功能(1967) Web開發(1951) HtmlCss(1944) C++(1922) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1878) .NETCore(1861) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Kotlin難點

    [toc] # 高階函式 高階函式是將函式用作引數或回傳值的函式,還可以把函式賦值給一個變數。 所有函式型別都有一個圓括號括起來的引數型別串列以及一個回傳型別:(A, B) -> C 表示接受型別分別為 A 與 B 兩個引數并回傳一個 C 型別值的函式型別。 引數型別串列可以為空,如 () -> A ......

    uj5u.com 2023-05-26 08:16:54 more
  • 詳細解讀Java中Map集合的底層原理(干貨+原始碼解讀)

    本文將為大家詳細講解Java中的Map集合,這是我們進行開發時經常用到的知識點,也是大家在學習Java中很重要的一個知識點,更是我們在面試時有可能會問到的問題。文章較長,干貨滿滿,建議大家收藏慢慢學習。文末有本文重點總結,主頁有全系列文章分享。技術類問題,歡迎大家和我們一起交流討論! ......

    uj5u.com 2023-05-26 08:11:48 more
  • Python集合 (set) 的增刪改查及 copy()方法

    集合是無序的,不重復的資料集合,它里面的元素是可哈希的(不可變型別),但是集合本身是不可哈希(所以集合做不了字典的鍵)的。 以下是集合最重要的兩點: 1、去重,把一個串列變成集合,就自動去重了。 2、關系測驗,測驗兩組資料之前的交集、差集、并集等關系。 ### 一、集合的創建 ```python s ......

    uj5u.com 2023-05-26 08:11:43 more
  • 【編程日記】搭建PyCharm集成開發環境

    # 0.相關確定 本教程使用的版本號為專業版PyCharm 2022.3.2,如果您是初學者,為了更好的學習本教程,避免不必要的麻煩,請您下載使用與本教程一致的版本號。 # 1.PyCharm的下載 官網下載:https://www.jetbrains.com/pycharm/download/ot ......

    uj5u.com 2023-05-26 08:06:24 more
  • 如何證明Servlet是單例的?

    Servlet是web體系里面最重要的部分,下面羅列幾道常見的面試題,小伙伴們一定要好好記住哈。 1.Servlet是單例的嗎,如何證明? Servlet一般都是單例的,并且是多執行緒的。如何證明Servlet是單例模式呢?很簡單,重寫Servlet的init方法,或者添加一個構造方法。然后,在web ......

    uj5u.com 2023-05-26 08:01:14 more
  • Rocksdb原理簡介

    Rocksdb作為當下nosql中性能的代表被各個存盤組件(mysql、tikv、pmdk、bluestore)作為存盤引擎底座,其基于LSM tree的核心存盤結構(將隨機寫通過資料結構轉化為順序寫)來提供高性能的寫吞吐時保證了讀性能。同時大量的并發性配置來降低compaction的影響。 ......

    uj5u.com 2023-05-26 07:55:59 more
  • 用go封裝一下封禁功能

    本篇為[用go設計開發一個自己的輕量級登錄庫/框架吧]的封禁業務篇,會講講封禁業務的實作,給庫/框架增加新的功能。原始碼:https://github.com/weloe/token-go ......

    uj5u.com 2023-05-26 07:50:53 more
  • 它來了!真正的 python 多執行緒

    哈嘍大家好,我是咸魚 幾天前,IBM 工程師 Martin Heinz 發文表示 python 3.12 版本回引入"Per-Interpreter GIL”,有了這個 Per-Interpreter 全域解釋器鎖,python 就能實作真正意義上的并行/并發 我們知道,python 的多執行緒/行程 ......

    uj5u.com 2023-05-26 07:50:49 more
  • ThreadLocal的應用及原理

    ## 1. ThreadLocal 是什么 JDK 對`ThreadLocal`的描述為: > 此類提供執行緒區域變數。這些變數與普通變數的不同之處在于,每個訪問一個變數的執行緒(通過其get或set方法)都有自己的、獨立初始化的變數副本。ThreadLocal 實體通常是類中的私有靜態欄位,這些欄位希 ......

    uj5u.com 2023-05-26 07:45:35 more
  • Java的CompletableFuture,Java的多執行緒開發

    # 三、Java8的CompletableFuture,Java的多執行緒開發 ## 1、CompletableFuture的常用方法 - 以后用到再加 ```properties runAsync() :開啟異步(創建執行緒執行任務),無回傳值 supplyAsync() :開啟異步(創建執行緒執行任務 ......

    uj5u.com 2023-05-26 07:35:06 more