您好,登錄后才能下訂單哦!
<p style="text-align:center;color:#42A5F5;font-size:2em;font-weight: bold;">前言
即使每天10點下班,其實需求很多,我也要用這腐朽的聲帶喊出:我要學習,我要寫文章!!
又是一篇Kotlin的文章,為啥...還不是因為工作需要。毫無疑問,最好的學習方式是通過官方文檔去學習。不過個人覺得官方文檔多多少少有一些不夠高效。
中文官方文檔
因此這篇是從我學習的個人視角以文檔的形式去輸出Kotlin語言基礎的學習。
不扯淡了,開整。
<p style="text-align:center;color:#42A5F5;font-size:2em;font-weight: bold;">正文
高階函數是將函數用作參數或返回值的函數。
個人為什么把這個語言特性放在第一位,因為我覺得這是我們Java語言中所不支持的。然而這個特性基本貫穿整個Kotlin語言體系。所以個人把它放到了第一位,也希望各位小伙伴能夠重視這個小小的特性。先看看一個小小的demo,感受一下這個特別特性:
// 函數定義
fun funtion(num: Int, innerFun: (Int) -> Int): Int {
return innerFun(num)
}
簡單解釋一下上邊的代碼。我們先看函數定義,這里定義了一個名為funtion并且返回值為Int的函數,此外這個函數接受一個Int參數和一個函數類型的參數(這個函數需要傳遞一個Int參數,并且返回一個Int值)。
接下來我們調用一下:
// 函數調用
val result = funtion(1) {
it + 666
}
對于Lambda來說,入參如果是一個的話可以用it來表示
說實話,第一次我看到這種調用的時候,是一臉懵逼的。不知道剛入坑的小伙伴是不是和我一樣的感受?因為這種寫法包含小tips:
我們的innerFun是可以被簡化為一個Lambda,而當Lambda作為函數的最后一個參數時,是可以將其寫在函數之外的。也就是Demo中的funtion(1){}。
此外我們要注意一點,這里我們的函數實例,并沒有return,這是因為。lambda 表達式中的最后一個表達式是返回值
實際上這就是相當于調用了funtion方法的倆個參數,咱們換一種傳統的寫法,二者是等價的:val inner = fun(num: Int): Int { return num + 1 } val result = funtion(1, inner)
OK,接下來咱們趁熱打鐵,再感受感受函數操作的“騷操作”。接下來我們看一看其實情況下的用法:
// 函數定義1 fun funtion(num: Int, innerFun: (Int, Int) -> Int): Int { return innerFun(num, num + 1) } // 函數調用1(上文提到,入參為1個可以用it表示,那么倆個或者多個呢?我們可以如下,自定義) val result = funtion(1) { num1, num2 -> num1 + num2 + 666 } // 函數調用2(除了Lambda的調用方式,我們還可以用匿名函數,二者是一樣的) val result = funtion(1, fun(num1: Int, num2: Int): Int { return num1 + num2 + 666 }
OK,關于高階函數的內容,就聊這么多,因為有了這個其實,很多內容也就很好上手了。接下來就讓我們一同看看基于高階函數的內置封裝。
個人覺得,Kotlin操作符中。開發中頗為常用的是集合操作符,比如我們有時需要對一些數據進行連續的轉化,我們可能會使用RxJava;
Observable.create(new ObservableOnSubscribe<List<CustomModel>>() {
@Override
public void subscribe(ObservableEmitter<List<CustomModel>> e) throws Exception {
// 省略構建List<CustomModel>
e.onNext(data);
}
}).flatMap(new Function<List<CustomModel>, ObservableSource<CustomModel>>() {
@Override
public ObservableSource<CustomModel> apply(List<CustomModel> customModels) throws Exception {
return Observable.fromIterable(customModels);
}
}).map(new Function<CustomModel, String>() {
@Override
public String apply(CustomModel customModel) throws Exception {
return customModel.name;
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
// 操作s
}
});
這里簡單,寫了一個RxJava的Demo:我們有一個List集合,先把它一個個發送,然后把每一個數據轉成String,最后去String進行處理。
而在Kotlin中,應對上述的需求,我們該怎么做?由于操作符的支持,我們可以極為方便的進行這類操作:
val data = arrayListOf<CustomModel>(// ...省略構建的過程)
val newData=data.map {
it.name
}.forEach {
// 操作it
}
用法很簡單,乍一看很唬人。但是其實很簡單,回憶一下我們再開篇奠定的高階函數的基礎。這里其實就是調用了data的擴展函數map(拓展函數是一種語法,可以拓展現有的類。比如這個map就是拓展了Iterable,下文我們會展開它的實現)。對它進行類型轉變,然后進而調用forEach自動對這個集合進行遍歷。
接下來讓我們點進去,看一看具體的實現:
// 注意看,這里map的**返回值**,是一個List<R>,也就是說最終將返回map后的類型集合。因此我們可以繼續進行鏈式調用。
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}
public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapTo(destination: C, transform: (T) -> R): C {
for (item in this)
destination.add(transform(item))
return destination
}
說白了,這里的集合操作符就是把轉化的實現通過參數的形式暴露出來,由我們自行去處理,其他的事情,有內部封裝去做。
當然,這其中還有很多有趣的操作符,各位小伙伴可以自行去了解。不過原理都是大同小異~
上述我們聊的是作用在集合上的操作符,說白了。它們就是拓展在對應集合類上的函數而已。那么可能有小伙伴會問,有沒有作用在對象上的?沒錯,是有的。也就是我們接下來要聊的:作用域函數。
其實很常見:
"Kotlin".let{
it.toInt()
}
"Kotlin".run{
this.toInt()
}
"Kotlin".apply{
}
"Kotlin".also{
}
public inline fun <T, R> T.let(block: (T) -> R): R
public inline fun <T, R> T.run(block: T.() -> R): R
public inline fun <T> T.apply(block: T.() -> kotlin.Unit): T
public inline fun <T> T.also(block: (T) -> kotlin.Unit): T
咱們看一下,它們哥四個的定義,其實很清晰。這里以返回值的類型,倆倆分類:
不過即使沒有入參,也可以通過this,得到本身。
上述函數的作用還是挺方便的,比如:
Model model ;
// ...省略初始化過程
if(model!=null){
// 省略大段的操作邏輯
}
這種寫法,在kotlin中可以這么寫:
model?.alse{
// 省略大段的操作邏輯
}
// 有需求我們可以繼續調用它的作用域函數
如果你還有一些else操作,那么沒轍了,kotlin中也只能老老實實if-else
當然,還有一些有趣的作用域函數,比如在Java中:
boolean isTure;
// 省略boolean判斷邏輯
if(isTure){
// 省略大段的操作邏輯
}
到Kotlin中可以這樣來搞:
某對象.takeIf{
// boolean判斷邏輯
}?.{
// 省略大段的操作邏輯
}
// 有需求我們可以繼續調用它的作用域函數
takeIf:會根據入參的函數的返回值(true/false),決定自己(takeIf)的返回值是null還是調用者。如果是false,那么就會返回null,因此這里使用?的方式繼續去調用后續操作。
我個人比較喜歡作用域函數, 因為可以省略很多if。接下來我們來換個稍稍復雜的邏輯:已知一個方法,入參是一個Model,我們要判斷當這個Model對象的age屬性大于10,打印這個Model對象的名字。
對于Java來說,我們可能這么寫:
public void fun(Model model) {
// 寫了3個if。
if (model != null) {
if (model.age>10){
if (model.name!=null){
// 打印model.name
}
}
}
}
class Model {
String name;
int age;
}
對于Kotlin來說,我們可以這么寫:
fun funtion(model : Model){
model?.takeIf{
it.age > 10
}?.let{
// 打印it.name
}
}
是不是簡潔了很多?但是單說簡潔這種東西,似乎并沒有什么卵用...不過寫起來,真的很爽!不信,大家可以試試~~
<p style="text-align:center;color:#42A5F5;font-size:2em;font-weight: bold;">尾聲
這篇文章,想聊的內容就這么多。個人認為其實理解了高階函數,(PS:不知道為啥起了個名叫高階函數,整得好像很高級似的。)Kotlin就可以很快的上手,并且能感受到Kotlin寫起來的爽快之處~
這里的確有些安利的意味。那是因為自己最開始對新技術其實接受度并不高,總認為新東西有各種各樣的問題...當自己去了頭條之后,才發現身邊的同事那種高昂的學習勁頭,(Kotlin?對他們來說不叫新東西...Jatpack,Flutter都已經在線上項目中跑了)自己還有什么理由說:求求別更新了,我學不動了...
還是那句話:干就完了!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。