目錄
1、定義
2、作用
3、函數:run
4、函數:let
5、函數:apply
5、函數:also
6、函數:takeIf
7、函數:takeUnless
8、函數:with
9、總結
1、定義
對象的擴充函數。
如下圖:1、紅色框内的就是pig對象所能調用的擴充函數(這些擴充函數對所有對象都适用)
2、綠色框内就是run擴充函數的源碼,具體講解這個擴充函數的作用
2、作用
可以在這些擴充函數中,對該對象進行進一步的處理。
3、函數:run
它的作用就是将這個函數所得到的值進行傳回。
- 注意:run函數隻能傳回它的最後一條語句的所得到的值,如下:result2傳回的是第二條語句 this.name + "長胖了" 的值。
- 解決:如果你想要傳回第一條語句的值,可以使用[email protected]方法進行傳回。
fun main() {
val pig = Pig("花姑娘", 300)
val result1 = pig.run {
this.name + "長胖了"
}
val result2 = pig.run {
this.name + "長胖了"
this.weight + 30
}
val result3 = pig.run {
[email protected] this.name + "長胖了"
this.weight + 20
}
println("result1=$result1")
println("result2=$result2")
println("result3=$result3")
}
//輸出結果
result1=花姑娘長胖了
result2=330
result3=花姑娘長胖了
4、函數:let
它的作用和run函數一樣都是對函數所得到的值進行傳回。
- 唯一不同:它需要将調用let函數的對象本身,傳入到Lambda閉包函數的參數中。
- 當然我們可以對這個參數進行簡寫(Lambda隻有一個參數的話,可以省略),省略之後,如果想要調用自身對象的屬性可以使用it
如下:let的閉包函數的參數pig1其實就是pig本身。
val pig = Pig("花姑娘", 300)
val newName = pig.let { pig1: Pig ->
pig1.name + "瘦了"
}
val newName1 = pig.let {
it.name + "瘦了"
}
println("newName=$newName")
println("newName1=$newName1")
//輸出結果
newName=花姑娘瘦了
newName1=花姑娘瘦了
我們可以簡單可一下它的源碼。這裡的let是一個範型方法,T代表對象本身,R代表Lambda閉包函數。
block:(T)-> R 可以看到在lambda函數中的參數就是對象本身T,
return block(this) 代表傳回lambda函數的運作結果,
至于中間的 contract 它其實就是一個契約函數,後面我們進行詳細講述。
/**
* Calls the specified function [block] with `this` value as its argument and returns its result.
*/
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
5、函數:apply
它的傳回對象是對象本身,是以我們可以用它對自身屬性進行一些操作,再傳回本身。(類似于集合的一些操作符)
後面我附上了源碼,可以看到return this,這個this,就是對象本身。
data class Chicken(var name: String, var weight: Int)
fun main() {
val chicken = Chicken("小母雞", 30)
val chickenNew = chicken.apply {
println("原來的名字:${this.name}")
this.name = "小花雞"
}
println("現在的名字:${chickenNew.name}")
}
//輸出結果
原來的名字:小母雞
現在的名字:小花雞
5、函數:also
源碼:
/**
* Calls the specified function [block] with `this` value as its receiver and returns `this` value.
*/
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}
它的作用和apply一樣,都是傳回自己,我們在這裡可以對對象本身進行操作, 然後再傳回。
差別:also需要将對象本身作為參數傳入到lambda函數的參數中,這個差別和run、let的差別一樣。
data class Chicken(var name: String, var weight: Int)
fun main() {
val chicken = Chicken("小母雞", 30)
val chickenAlso = chicken.also { chicken1: Chicken ->
println("原來的重量:${chicken1.weight}")
chicken1.weight = 40
}
println("現在的重量:${chickenAlso.weight}")
}
//輸出結果
原來的重量:30
現在的重量:40
源碼:
/**
* Calls the specified function [block] with `this` value as its argument and returns `this` value.
*/
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.also(block: (T) -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block(this)
return this
}
6、函數:takeIf
//源碼:
/**
* Returns `this` value if it satisfies the given [predicate] or `null`, if it doesn't.
*/
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
}
return if (predicate(this)) this else null
}
從源碼可以看出,它最後傳回的是根據Lambda閉包函數predicate的boolean值來決定的。
如果是true就傳回對象本身,
如果是false就傳回null。
- 作用:這個函數的作用的話,我們可以在takeif裡邊對對象本身的屬性進行判斷,如果符合條件就輸出,否則就傳回null。
- 注意1:在takeif裡邊最後一條語句必須是判斷語句,否則就會報錯。
- 注意2:如果有多條判斷語句,我們可以根據[email protected] 來決定傳回那條語句的boolean值。
data class Cat(var name: String, var weight: Int)
fun main() {
val cat=Cat("小花",10)
val cat1=cat.takeIf {catP: Cat ->
catP.weight>10
}
val cat2 =cat.takeIf {catP: Cat ->
catP.weight<=10
}
val cat3=cat.takeIf {catP: Cat ->
[email protected] catP.weight>10
catP.weight<10
//1+1//報錯
}
println("cat1=$cat1")
println("cat2=$cat2")
println("cat3=$cat3")
}
//輸出結果
cat1=null
cat2=Cat(name=小花, weight=10)
cat3=null
7、函數:takeUnless
它的作用和takeif一樣,不同的是它根據閉包函數predicate的boolean值傳回的結果相反。
如果是true傳回null,
如果是false傳回對象本身。
data class Cat(var name: String, var weight: Int)
fun main() {
val cat = Cat("小花", 10)
val cat1 = cat.takeIf { catP: Cat ->
catP.weight > 10
}
val cat12 = cat.takeUnless {
it.weight > 10
}
println("cat1=$cat1")
println("cat12=$cat12")
}
//輸出結果
cat1=null
cat12=Cat(name=小花, weight=10)
8、函數:with
//源碼
/**
* Calls the specified function [block] with the given [receiver] as its receiver and returns its result.
*/
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return receiver.block()
}
從源碼我們看到它不需要對象來調用它,它其實是一個頂級函數,也就shi你在哪裡都可以調用這個函數。
但是它需要兩個參數,一個是一個對象receiver,另一個是閉包函數block
它的傳回值就是參數對象receiver對閉包函數block的調用結果
- 可見它的作用可以有很多,比對一個對象進行屬性的修改,或這對一個view進行一系列操作,它看起來可以讓代碼實作了子產品化。
data class Cat(var name: String, var weight: Int)
fun main() {
val cat = Cat("小花", 10)
val result=with(cat){
this.name="小白"
this.weight=11
1+1
}
println("cat.name=${cat.name}")
println("cat.weight=${cat.weight}")
println("result=$result")
}
//輸出結果
cat.name=小白
cat.weight=11
result=2
9、總結
這些作用域函數的作用還是具有很多的開放性,你可以用他們來做很多邏輯指派操作。這就要看你的發揮了。
data class Cat(var name: String, var weight: Int)
fun main() {
val cat = Cat("小花", 10)
val newName = cat.also {
it.name = it.name + "+1"
}.takeIf {
it.weight <= 10
}?.apply {
this.name = this.name + "+2"
}?.run {
[email protected] name + "+3"
}
println("newName=$newName")
}
//輸出結果
newName=小花+1+2+3