-
by 委托模式
Kotlin中跨晴,委托的實現(xiàn)依靠于關鍵字 by 费封,by表示將抽象主題的實例(by后邊的實例)保存在代理類實例的內(nèi)部,比如SportsManager類繼承于ISports接口,并可以ISports接口的所有的 public 方法委托給一個指定的對象末患。
類委托:
interface ISports {
fun doSports()
}
class SwimForSports: ISports{
override fun doSports() {
println("do swim")
}
}
class SportsManager(sport: ISports): ISports by sport
fun main(args: Array<String>) {
val swimSports: SwimForSports = SwimForSports()
SportsManager(swimSports).doSports()// Log:do swim
}
在SportsManager聲明中,by子句表示,將sport保存在SportsManager的對象實例內(nèi)部隧膏,而且編譯器將會生成繼承自 ISports 接口的所有方法, 并將調(diào)用轉(zhuǎn)發(fā)給sport。
委托屬性:
所謂的委托屬性魏宽,就是對其屬性值的操作不再依賴于其自身的getter()/setter()方法曲稼,是將其托付給一個代理類湖员,從而每個使用類中的該屬性可以通過代理類統(tǒng)一管理贫悄,再也不用在每個類中,對其聲明重復的操作方法娘摔。
當我們使用屬性的get或者set的時候窄坦,屬性委托的getValue和setValue就會被調(diào)用。
fun main(args: Array<String>) {
val bigHeadSon = BigHeadSon()
bigHeadSon.money = 100//收到100塊壓歲錢
println(bigHeadSon.money)//50 被代保管了一半
}
class BigHeadSon {
var money: Int by Mother()
}
class Mother {
var moneySon = 0
var moneyMother = 0
operator fun getValue(bigHeadSon: BigHeadSon, property: KProperty<*>): Int {
return moneySon
}
operator fun setValue(bigHeadSon: BigHeadSon, property: KProperty<*>, i: Int) {
moneySon = i / 2
moneyMother = i / 2
}
}
延遲加載(Lazy)
lazy()是一個函數(shù), 接受一個Lambda表達式作為參數(shù), 返回一個Lazy類型的實例,這個實例可以作為一個委托, 實現(xiàn)延遲加載屬性(lazy property): 第一次調(diào)用 get() 時, 將會執(zhí)行 lazy() 函數(shù)受到的Lambda 表達式,然后會記住這次執(zhí)行的結(jié)果, 以后所有對 get() 的調(diào)用都只會簡單地返回以前記住的結(jié)果.
惰性加載
by lazy 放到成員變量中凳寺,可以單獨存在
by lazy 返回值就是最后一行
by lazy 是線程安全的
fun main(args: Array<String>) {
val lazy = Lazy()
println(lazy.name)
println(lazy.name)
println(lazy.name)
}
class Lazy {
val name: String by lazy {
println("只初始化一次")
"懶加載"
}
}
-
it Lambda語法
it 來使用此參數(shù)鸭津。it可表示為單個參數(shù)的隱式名稱逆趋,是Kotlin語言約定的魄眉。
// 即it不是`Kotlin`中的關鍵字冀值【盥可用于變量名稱
val it : Int = 0
//在 Lambdas 表達式中,大括號與表達式間要有空格焰扳,箭頭與參數(shù)和函數(shù)體間要有空格
list.filter { it > 10 }.map { element -> element * 2 }
在短的且不嵌套的Lambdas中倦零,建議使用it替換參數(shù),有嵌套而已有多個參數(shù)的Lambdas中吨悍,就不能用it來替換參數(shù)扫茅,必須明確聲明參數(shù)。
-
Kotlin中l(wèi)et, apply, run, with, also函數(shù)
1, 『let』操作符:如果對象的值不為空育瓜,則允許執(zhí)行這個方法葫隙。
場景一: 最常用的場景就是使用let函數(shù)處理需要針對一個可null的對象統(tǒng)一做判空處理。
//判斷object為null的操作
object?.let{//表示object不為null的條件下躏仇,才會去執(zhí)行l(wèi)et函數(shù)體
it.todo()
}
場景二: 然后就是需要去明確一個變量所處特定的作用域范圍內(nèi)可以使用
另一種用途 let函數(shù)的使用的一般結(jié)構(gòu)
object.let{
it.todo()//在函數(shù)體內(nèi)使用it替代object對象去訪問其公有的屬性和方法
...
}
從源碼let函數(shù)的結(jié)構(gòu)來看它是只有一個lambda函數(shù)塊block作為參數(shù)的函數(shù),調(diào)用T類型對象的let函數(shù)恋脚,則該對象為函數(shù)的參數(shù)。在函數(shù)塊內(nèi)可以通過 it 指代該對象钙态。返回值為函數(shù)塊的最后一行或指定return表達式慧起。
//Java
if (currentUser != null) {
text.setText(currentUser.name)
}
//instead Kotlin
user?.let {
println(it.name)
}
//源碼
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
2,with函數(shù)的kotlin和Java轉(zhuǎn)化
with函數(shù)和前面的幾個函數(shù)使用方式略有不同,因為它不是以擴展的形式存在的册倒。它是將某對象作為函數(shù)的參數(shù),在函數(shù)塊內(nèi)可以通過 this 指代該對象磺送。返回值為函數(shù)塊的最后一行或指定return表達式驻子。
可以看出with函數(shù)是接收了兩個參數(shù)灿意,分別為T類型的對象receiver和一個lambda函數(shù)塊,所以with函數(shù)最原始樣子如下:
//kotlin
fun main(args: Array<String>) {
val user = User("Kotlin", 1, "1111111")
val result = with(user) {
println("my name is $name, I am $age years old, my phone number is $phoneNum")
1000
}
println("result: $result")
}
//java
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
User user = new User("Kotlin", 1, "1111111");
String var4 = "my name is " + user.getName() + ", I am " + user.getAge() + " years old, my phone number is " + user.getPhoneNum();
System.out.println(var4);
int result = 1000;
String var3 = "result: " + result;
System.out.println(var3);
}
//源碼
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return receiver.block()
}
3,run函數(shù)的kotlin和Java轉(zhuǎn)化
run函數(shù)實際上可以說是let和with兩個函數(shù)的結(jié)合體崇呵,run函數(shù)只接收一個lambda函數(shù)為參數(shù)缤剧,以閉包形式返回,返回值為最后一行的值或者指定的return的表達式域慷。
//kotlin
fun main(args: Array<String>) {
val user = User("Kotlin", 1, "1111111")
val result = user.run {
println("my name is $name, I am $age years old, my phone number is $phoneNum")
1000
}
println("result: $result")
}
//java
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
User user = new User("Kotlin", 1, "1111111");
String var5 = "my name is " + user.getName() + ", I am " + user.getAge() + " years old, my phone number is " + user.getPhoneNum();
System.out.println(var5);
int result = 1000;
String var3 = "result: " + result;
System.out.println(var3);
}
//源碼
public inline fun <T, R> T.run(block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
4,apply函數(shù)的kotlin和Java轉(zhuǎn)化
從結(jié)構(gòu)上來看apply函數(shù)和run函數(shù)很像荒辕,唯一不同點就是它們各自返回的值不一樣,run函數(shù)是以閉包形式返回最后一行代碼的值犹褒,而apply函數(shù)的返回的是傳入對象的本身抵窒。
//kotlin
fun main(args: Array<String>) {
val user = User("Kotlin", 1, "1111111")
val result = user.apply {
println("my name is $name, I am $age years old, my phone number is $phoneNum")
1000
}
println("result: $result")
}
//java
public final class ApplyFunctionKt {
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
User user = new User("Kotlin", 1, "1111111");
String var5 = "my name is " + user.getName() + ", I am " + user.getAge() + " years old, my phone number is " + user.getPhoneNum();
System.out.println(var5);
String var3 = "result: " + user;
System.out.println(var3);
}
}
//源碼
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}
5, also函數(shù)編譯后的class文件
also函數(shù)的結(jié)構(gòu)實際上和let很像唯一的區(qū)別就是返回值的不一樣,let是以閉包的形式返回叠骑,返回函數(shù)體內(nèi)最后一行的值李皇,如果最后一行為空就返回一個Unit類型的默認值。而also函數(shù)返回的則是傳入對象的本身
//kotlin
fun main(args: Array<String>) {
val result = "testLet".also {
println(it.length)
1000
}
println(result)
}
//java
public final class AlsoFunctionKt {
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
String var2 = "testLet";
int var4 = var2.length();
System.out.println(var4);
System.out.println(var2);
}
}
區(qū)別總結(jié)
非擴展函數(shù)的 run
fun <R> run(block: () -> R): R
一個無參數(shù)的lambda表達式宙枷,允許自定義返回值
這不是個擴展函數(shù)掉房,因此不能用對象點出來
但因為是頂級函數(shù),所以可以在任何地方直接調(diào)用慰丛,其一般用途應該主要是這種代碼:
run {
// do something
}
val result = run {
// do something
}
run卓囚、apply
fun <T, R> T.run(block: T.() -> R): R
fun <T> T.apply(block: T.() -> Unit): T
這兩個函數(shù)的共同點在于,參數(shù)都是T.()
因此在lambda中要以this來表示當前對象
不同點在于:run可以自定義返回值诅病,apply只能返回當前對象
使用示例:
"Hello"
.run { this + " World" } // 在自身后面拼接字符串捍岳,并將結(jié)果返回
.apply { println(this) } // 打印剛才拼接好的字符串
also、let
fun <T, R> T.let(block: (T) -> R): R
fun <T> T.also(block: (T) -> Unit): T
這兩個函數(shù)跟上面的兩個功能幾乎相同睬隶,可以看出let對run锣夹,also對apply
區(qū)別在于參數(shù)的lambda的參數(shù)部分變成了(T),因此要以it來表示當前對象
使用示例:
"Hello"
.let { it + " World" } // 在自身后面拼接字符串苏潜,并將結(jié)果返回
.also { println(it) } // 打印剛才拼接好的字符串
with
fun <T, R> with(receiver: T, block: T.() -> R): R
這個函數(shù)的作用是以一個指定對象的身份去調(diào)用特定的代碼银萍,并允許自定義返回值
感覺主要是為了新寫法設計的,一般用途應該是這樣的:
with ("Hello") {
val str = this + " World"
println(str)
}
takeIf恤左、takeUnless
fun <T> T.takeIf(predicate: (T) -> Boolean): T?
fun <T> T.takeUnless(predicate: (T) -> Boolean): T?
這兩個方法可以執(zhí)行一段代碼贴唇,這段代碼可以返回一個布爾值來控制之后的流程
對于takeIf:如果返回true,則這個函數(shù)會返回this飞袋,否則會返回null
而對于takeUnless則剛好與takeIf的行為相反
使用示例:
"Hello"
.takeIf { it.length == 5 } // 判斷字符串的長度等于 5戳气,返回 true,因此 takeIf 函數(shù)會返回 this
?.run { this + " World!" } // 拼接字符串巧鸭,因為上一句沒返回 null瓶您,所以可以正常執(zhí)行
?.apply(::println) // 打印剛剛拼好的字符串
?.takeUnless { it.length == 5 } // 判斷字符串的長度等于 5,返回 false,因此 takeUnless 函數(shù)會返回 this
?.apply(::println) // 打印剛剛拼好的字符串
?.takeIf { it.length == 5 } // 判斷字符串的長度等于 5呀袱,返回 false贸毕,因此 takeIf 函數(shù)會返回 null
?.apply(::println) // 這句不會執(zhí)行!因為上一句返回了 null
```
文章來自:
https://blog.csdn.net/u013064109/article/details/78786646
http://www.reibang.com/p/1f139e3cfb49