读书笔记『Kotlin实战』
P18:在Kotlin中沒有聲明數(shù)組類型的特殊語法,數(shù)組就是類
P19:在Kotlin中if是有結(jié)果的表達(dá)式
fun mac(a:Int,b:Int):Int{ return if(a>b) a else b}P25:自定義訪問器
class Retangle(val height:Int, val width:Int) {val isSqual:Booleangen() { return height == width } }P30:在"when"中使用任意對象
fun mix(cl:Color, c2:Color) {when(setOf(c1, c2)) {setOf(RED, YELLOW) -> ORANGEsetOf(YELLOW, BLUE) -> GREENsetOf(Blue, VIOLET) -> INDIGO} }P37:迭代數(shù)字:區(qū)間和數(shù)列
- 區(qū)間:for( i in 1 … 100 ) { print( i ) }
- 步長區(qū)間:for( i in 100 downTo 1 step 2 )
- 半閉合區(qū)間:for( x in 0 util size ),等同于for( x in 0 … size-1 )
P38:迭代map
- for( letter.binary ) in list.withIndex() { “$index: $element”}
P41:Kotlin中throw結(jié)構(gòu)是一個表達(dá)時刻,能作為另一個表達(dá)式的一部分使用:
val percentPage = if( num in 0..100) number else IllegalArgumentExcetion()P49:在Kotlin中方法參數(shù)可以指定默認(rèn)值
fun testDefaultArg(a:Int,b:Int = 11,c:Int=22) {println("$a,$b,$c") } >>>println("$a,$b,$c") //輸出:9,11,22P51:頂層函數(shù)和頂層方法都會編譯成靜態(tài)成員,如果想要public static final,可以使用const修飾頂層屬性。
P53:擴(kuò)展函數(shù)式一個類的成員函數(shù),不過它定義在類的外面,擴(kuò)展函數(shù)不能訪問私有或受保護(hù)的成員
fun String lastChar():char = this.get(this.lenght - 1)P54:如果導(dǎo)入的函數(shù)存在重名,可以使用as來標(biāo)識別名
import strings.lastChar as lastP57:擴(kuò)展函數(shù)不存在重寫,因為Kotlin會把它們當(dāng)做靜態(tài)函數(shù)對待。另外成員函數(shù)的優(yōu)先級高于擴(kuò)展函數(shù)。
P60:中綴調(diào)用:var map = mapOf(1 to “one”,2 to “two”);解構(gòu)聲明:val(number,name) = 1 to “one”
P69:Kotlin中接口是可以包含屬性的。Kotlin中嵌套的類默認(rèn)并不是內(nèi)部類:它們并沒有包含對其他外部類的隱式引用。
P72:如果繼承有兩個相同的方法,需要使用"<>"顯式地指定實現(xiàn)哪一個
override fun showOff {super<Callable>.showOff()super<Focusable>.showOff() }P73:Kotlin中的類默認(rèn)是final,如果希望這個類能夠被繼承,需要使用open修飾符修飾。已經(jīng)重寫了的方法,如果沒有final修飾,表明它是開放的。
P75:Kotlin中默認(rèn)的可見性是public;Kotlin中一個外部類不能訪問嵌套類的private成員。
P77:在Java中,在一個類中聲明另一個類時,這個類默認(rèn)是內(nèi)部類,內(nèi)部類持有外部類的引用。要去除這種引用,需要把內(nèi)部類聲明成static的。在Kotlin中沒有顯式修飾符的嵌套類與Java中的static是一樣的,要把它變成內(nèi)部類,需要使用inner修飾。
P79:密封類:用sealed修飾的類對可能創(chuàng)建的子類做出了嚴(yán)格的限制。所有直接子類必須嵌套在父類中。sealed修飾符隱含這個類是一個open類。
P82:如果所有的構(gòu)造方法參數(shù)都有默認(rèn)值,編譯器會生成一個額外的不帶參數(shù)的構(gòu)造方法來使用這些默認(rèn)值。
P85:在Kotlin中,接口可以包含抽象屬性聲明,者意味著實現(xiàn)User接口的類需要提供一個取得抽象屬性的方式。
interface User { val nickname:String} class PrivateUser(override val nickname:String):UserP88:在非空屬性上使用lateInit修飾符表明這個屬性會將初始化推遲到構(gòu)造方法被調(diào)用后。
P90:如果想進(jìn)行引用比較,可以使用**=運算符,這與Java中的**效果一樣。
P92:Kotlin中數(shù)據(jù)類(data class)會自動幫你生成通用方法,如:toString、equals、hashCode。另外還多生成了一個copy方法,用于修改val參數(shù)。
P93:當(dāng)你需要向類中添加一些行為的時候,Kotlin中提供了類委托的支持,無論什么時候?qū)崿F(xiàn)一個接口,都可以使用by關(guān)鍵字將接口的實現(xiàn)委托到另外一個對象。好處是不需要實現(xiàn)一堆接口中定義的方法,如:
class DelegatingCollection<T>(innerList:Collection<T> = ArrayList<T>()):Collection<T> by innerList{}P95:Kotlin中object關(guān)鍵字的核心是:定義一個類并同事創(chuàng)建一個實例。對象聲明:定義單例的一種方式,對象聲明中可以包含屬性、方法、初始化語句塊等的聲明,但是不能包含構(gòu)造方法,因為對象聲明在定義時就創(chuàng)建了對象,不需要構(gòu)造方法;在Java中調(diào)用對象聲明使用INSTANCE來訪問靜態(tài)對象。
P98:伴生對象:可以持有工廠方法和其他與這個類相關(guān),但在調(diào)用時并不依賴類實現(xiàn)的方法。它們的成員可以通過類名來訪問。
P103:對象表達(dá)式:用來替換Java的匿名內(nèi)部類。和Java匿名內(nèi)部類只能擴(kuò)展一個類或實現(xiàn)一個接口不同,Kotlin的匿名對象可以實現(xiàn)多個接口或不實現(xiàn)接口。另外對象表達(dá)式中的代碼可以訪問創(chuàng)建它的函數(shù)中的變量,訪問并沒有被限制在final變量,可以在代碼中修改變量值。(對于非final變量來說,它的值被封裝在一個特殊的包裝器中,這樣你就可以改變這個值,而這個包裝器的引用會和lambda代碼一起存儲)
P108:Lambdab表達(dá)式的語法:{ x:Int,y:Int -> x + y },實例:people.maxBy ({p:Person -> p.age}) =(如果lambda是函數(shù)調(diào)用的最后一個實參,它可以放在括號外面)> people.maxBy (){p:Persion -> p.age} =(當(dāng)lambda時唯一的實參,可以去掉括號)> people.maxBy{p:person -> p.age} =(和局部變量一樣,如果lambda參數(shù)的類型可以被推導(dǎo)出來,就可以省略)> people.maxBy{p -> p.age} =(如果當(dāng)前上下文只有一個參數(shù),且能被推導(dǎo)出類型,可以使用)> people.maxBy{ it.age }
P114:成員引用,提供了簡明語法,來創(chuàng)建一個調(diào)用的單個方法(普通函數(shù),構(gòu)造函數(shù)等)或者訪問單個屬性的函數(shù)值。使用雙冒號::來實現(xiàn),如:
fun salute() = println("Salute!") >>> run(::salute) //引用頂級函數(shù)P117:filter函數(shù)可以從集合中移除你不想要的元素,但它不會改變這些元素;map函數(shù)對集合中的每一個元素應(yīng)用給定的函數(shù)并把結(jié)果收集到一個新集合中。
val list = listOf(1,2,3,4) >>> println(list.map{ it * it}) //輸出[1,4,9,16]P118:Kotlin中,可以使用all、any、count、find、!all來檢查集合中的所有元素是否符合某個條件,如:
val canBeInClub27 = { it.age <= 27} //條件 val people = listOf(Person("A",27),Person("B",22)) >>>println(peole.all(canBeInClub27)) //輸出:falseP119:使用groupBy把元素按不同的特征劃分為不同的分組。如:
val p = listOf(Person("A",1),Person("B",1),Person("C",2)) >>>println(p.groupBy{ it.age }) //輸出{1=[Person(name=A, age=1), Person(name=B, age=1)], 2=[Person(name=C, age=2)]},有List轉(zhuǎn)換成了Map<Int,List<Person>>P120:flatMap根據(jù)實參給定的函數(shù)對集合中的每個元素做變換,然后把多個列表合并(或者說平鋪)成一個列表。而如果不需要做任何變換,只需要平鋪一個集合,可以使用flatter函數(shù)。
P121:Kotlin惰性集合操作的入口是Sequence接口,這個接口中只包含一個iterator方法,用來從序列中獲取值;Sequence的強(qiáng)大之處在于序列中的元素求值是惰性的,因此使用序列可以更高效的對集合元素執(zhí)行鏈?zhǔn)讲僮?#xff0c;而不需要創(chuàng)建額外的集合來保存過程中產(chǎn)生的中間結(jié)果。
P123:序列操作:sequence.map{ … }.filter{ … }.toList(),其中map和filter是中間操作,是惰性的,toList()是末端操作,返回結(jié)果。所謂惰性就是,只有在請求結(jié)果時才會真的進(jìn)行中間操作。另外,序列中時逐元素處理的,處理完一個元素的全部中間操作,才會進(jìn)行下一個,意味著不會發(fā)生任何變換。
P125:使用generateSequence函數(shù)給定序列中的前一個元素,這個函數(shù)會計算出下一個元素。
val naturalNumbers = generateSequence(0){ it + 1} val numbersTo100 = naturalNumbers.takeWhile{ it <= 100} >>>println(numbersTo100.sum()) //同樣的,numbersTo100也是惰性操作,只有調(diào)用sum()請求結(jié)果是才會進(jìn)行計算P130:注意lambda內(nèi)部沒有匿名對象那樣的this:沒有辦法引用到lambda轉(zhuǎn)換成的匿名類實例。從編譯器的角度來看,lambda是一個代碼塊,而不是一個對象,而且也不能把它當(dāng)成對象引用。Lambda中的this引用指向的是包圍它的類。
P131:帶接收者的lambda:在lambda函數(shù)體內(nèi)可以調(diào)用一個不同對象的方法,而且無須借助任何額外限定符;如with函數(shù):
fun alphabet():String{val _sb = StringBuilder()return with(_sb) { //實際上是一個接收兩個參數(shù)的函數(shù),第一個函數(shù)時_sb,第二個函數(shù)時lambda,with函數(shù)把它的第一個參數(shù)轉(zhuǎn)換成第二個參數(shù)的接收者,可以使用this指代接收者,this也可以省略。for(letter in 'a' .. 'z') {this.append(letter) //this}this.toString()} }P134:apply被聲明成一個擴(kuò)展函數(shù)。它的接收者變成了作為實參的lambda的接收者。類似于Builder,如:
TextView(context).apply { text = "Sample Text"textSize = 20.0 }P138:Kotlin中的可空類型特性是為了把運行的空指針異常轉(zhuǎn)變?yōu)榫幾g期的錯誤檢測。問號可以加在任何類型的后面來表示這個類型的變量可以存儲null引用:
Type? = Type or null可空標(biāo)識符(?)最重要的操作是和null進(jìn)行比較,一旦你進(jìn)行了比較,編譯器會記住,并且再這次比較發(fā)生的作用域內(nèi)把這個值當(dāng)做非空對象類對待。
P141:安全調(diào)用符(?.),它允許你把一次null檢查和一次方法調(diào)用合并成一個操作。如:
s?.toUpperCase() => if(s != null) s.toUpperCase() else nullP143:Elvis(?:)運算符接收兩個運算數(shù),如果第一個運算數(shù)不為null,運算結(jié)果就是第一個運算數(shù);如果第一個運算數(shù)為null,結(jié)果就是第二個運算數(shù)。如:
fun strLenSafe(s:String?):Int = s ?. length ?: 0 >>>println(strLenSafe(null)) //輸出:0 //結(jié)合Exception val address = person.company?.address ?: throw IllegalArgumentException("No address")P145:安全轉(zhuǎn)換:**as?**經(jīng)常Elvis運算符結(jié)合使用,如:
val otherPerson = o as? Person?: return falseP146:非空斷言(!!),可以將任何值轉(zhuǎn)換成非空類型。如果對null值做非空斷言,則會拋出異常。明確告訴編譯器知道可能為空,也愿意接受異常。
P148:let函數(shù)可以把一個調(diào)用它的對象變成lambda表達(dá)式的參數(shù)。如:
if(email!= null) sendEmailTo(email) -> email?.let{ email -> sendEmailTo(email)}P149:Kotlin通常要求你在構(gòu)造方法中初始化所有屬性,如果某個屬性是非空類型,你就必須提供非空的初始化值。如果你使用可空類型,意味著該屬性的每一次訪問都需要null檢查或者**!!**運算符;延遲初始化標(biāo)識符(lateinit)只能修飾var,因為val是final的,在編譯期就確定了其變量值,也不存在延遲初始化的需求。
P153:**Kotlin中所有泛型類和泛型函數(shù)的類型參數(shù)默認(rèn)都是可空的。**要是類型參數(shù)非空,必須要為它指定一個非空的上界,如:
fun <T:Any> printHashCode(t:T) {println(t.hashCode()) }P154:Kolin把那些定義在Java代碼中的類型看成平臺類型,當(dāng)調(diào)用java中的方法時處理參數(shù),或者重寫java接口時處理參數(shù)。參數(shù)可以是可空也可以是非空的,需要小心處理。
P160:Kotlin不會自動地把數(shù)字從一種類型轉(zhuǎn)換成另外一種,即使是轉(zhuǎn)換成范圍更大的數(shù)據(jù)類型。每種接觸類型都有轉(zhuǎn)換函數(shù),如:toInt(),toLong(),toShort()等。equals除了會比較兩個元素中存儲的值,還會比較裝箱類型。
P165:List<Int?> 表示列表中的元素可空,List? 表示整個列表可空,但是其中的元素不可空。
P167:Kotlin的集合設(shè)計和Java有所不同,它把訪問集合數(shù)據(jù)的接口(kotlin.collections.Collection)和修改集合數(shù)據(jù)的接口(kotlin.collections.MutableCollection,繼承了Collection接口)
P168:只讀集合不一定是不可變的,當(dāng)一個變量同時被只讀集合和可變集合引用時,他就可能被改變。
P173:Kotlin中的數(shù)組是一個帶有類型參數(shù)的類,創(chuàng)建數(shù)組的方式有包含:arrayOf、arrayOfNulls、以及Array構(gòu)造方法接收數(shù)組大小和一個lambda表達(dá)式,調(diào)用lambda表達(dá)式來創(chuàng)建每一個數(shù)組元素。如:
val letters = Array<String>(26) {i -> ('a' + i).toString() }P174:使用toTypedArray可以將集合中的元素按照元素類型轉(zhuǎn)換成對應(yīng)的數(shù)組;Kotlin中數(shù)組類型包含的類型參數(shù)始終會變成對象類型,想要在數(shù)組中包含基礎(chǔ)類型,需要使用特殊的數(shù)組類,如IntArray、BooleanArray等。
P180:重載算數(shù)運算符,不能定義自己的運算符。Kolin限定了你能重載哪些運算符,以及你需要在你的類中定義的對應(yīng)名字的函數(shù)(如:plus、minus、times、div、mod)。具體如下:
data class Point(val x:Int,val y:Int) {operator fun plus(other:Point):Point {return Point(x + other.x,y + other.y)} } >>> println(Point(2,4) + Point(3,6)) //輸出:Point(x=5,y=10)P189:在Kotlin中,下標(biāo)運算符是一個約定。使用下標(biāo)運算符讀取元素會被轉(zhuǎn)換為get運算符方法的調(diào)用,并且寫入元素將調(diào)用set。如下,其實是個擴(kuò)展函數(shù):
operator fun Point.get(index:Int):Int {return when(index) {0 -> x1 -> yelse -> throw IndexOutOfBoundsException("Invaild coordinate $index")} } >>>println(Point(11,22)[0]) //輸出:11P195:屬性委托,可以把一個值的讀取委托給別的輔助對象,會為輔助對象生成get、set方法,當(dāng)讀取屬性值的時候調(diào)用get方法。屬性委托的一種常見用法是懶加載:
class Person(val name:String) {val emails by lazy {loadEmails(this)} }P207:高階函數(shù)就是以另一個函數(shù)作為參數(shù)或者返回值的函數(shù)。在Kotlin中,函數(shù)可以用lambda或者函數(shù)引用來表示。高階函數(shù)語法:(參數(shù)類型列表) -> 返回值類型,需要注意的是,一個函數(shù)類型聲明總是需要一個顯式的返回類型,在這種場景下Unit是不能省略的。如下:
(int,String) -> Unit高階函數(shù)作為參數(shù)使用一:
fun twoAndThree(operation:(Int,Int) -> Int) {val result = operation(2,3)println("The result is $result") } >>>twoAndThree({a,b -> a * b}) //輸出:The result is 6 >>>twoAndThree({a,b -> a + b}) //輸出:The result is 5高階函數(shù)作為參數(shù)使用二:
fun String.filter(predicate:(Char) -> Boolean):String {var sb = StringBuilder()for(index in 0 until length) {val element = get(index)if(predicate(element)) sb.append(element)}return sb.toString() } >>>println("ab1c".filter { it in 'a' .. 'z' }) //輸出:abcP211:一個函數(shù)類型的變量時FunctionN接口的一個實現(xiàn),Kotlin標(biāo)準(zhǔn)庫定義了一系列的接口,Function0,Function1<P1,R),Function<P1,P2,R>等。每個接口定義了一個invoke方法,調(diào)用這個方法就會執(zhí)行函數(shù)。
P214:返回函數(shù)的函數(shù),really cool!,聲明一個返回另一個函數(shù)的函數(shù),需要指定一個函數(shù)類型作為返回類型。
enum class Delivery {STANDARD,EXPEDITED} class Order(val itemCount:Int) fun getShippingCostCalculator(delivery: Delivery):(Order) -> Double {if(delivery == Delivery.EXPEDITED) {return { order -> 6 + 2.1 * order.itemCount}}return { order -> 1.2 * order.itemCount} }P218:lambda表達(dá)式會被正常的編譯成匿名類,這表明沒調(diào)用一次lambda表達(dá)式,一個額外的類就會被創(chuàng)建。并且如果lambda捕捉了某個變量,那么每次調(diào)用的時候都會創(chuàng)建一個新的對象。這會帶來運行時的額外開銷,導(dǎo)致使用lambda比使用一個直接執(zhí)行的相同代碼的函數(shù)效率更低。當(dāng)一個函數(shù)被聲明為inline時,它的函數(shù)體是內(nèi)聯(lián)的,換句話說,函數(shù)體會直接替換到函數(shù)被調(diào)用的地方,而不是被正常調(diào)用。
P221:如果lambda作為參數(shù)被調(diào)用,這樣的代碼能被容易的內(nèi)聯(lián),如果lambda在某個地方被保存起來,此時lambda表達(dá)式將不能被內(nèi)聯(lián),因為必須要有一個包含這些代碼的對象存在。
P226:只有在以lambda作為參數(shù)的函數(shù)是內(nèi)聯(lián)函數(shù)的時候才能從更外層的函數(shù)返回(return)。一個非內(nèi)聯(lián)函數(shù)可以把它的lambda保存在變量中,可能在函數(shù)返回后繼續(xù)使用。可以使用標(biāo)簽,從局部返回:
fun lookForAlice2(boys:List<Boy>) {boys.forEach aa@{if(it.name == "Alice") {println("Found!")return@aa}}println("Alice is not found") } >>>forEach是一個Kotlin自帶的內(nèi)聯(lián)函數(shù),這里使用標(biāo)簽從局部返回,不會執(zhí)行println語句代碼229:return從最近使用fun關(guān)鍵字聲明的函數(shù)返回,在匿名函數(shù)中,不帶標(biāo)簽的return會從匿名函數(shù)返回,而不是從包含匿名函數(shù)的函數(shù)返回。
P236:和Java中使用關(guān)鍵字extends來約束泛型形參上界不同,Kotlin中使用**?*來約束上界,如下:
fun <T : Number> List<T>.sum() : T一旦指定了類型形參T的上界,你就可以調(diào)用定義在上界類中的方法。如:
fun <T:Number> oneHalf(value:T):Double {return value.toDouble() / 2.0 }P237:默認(rèn)的泛型參數(shù)的上界是Any,如果想限定實參為非空的,可以指定T : Any;可以為一個類型參數(shù)指定多個約束,如下:
fun <T> ensureTrailingPeriod(seq:T):T where T:CharSequence,T:Appendable {if(!seq.endsWith('.')) {seq.append('.')}return seq } >>>println(ensureTrailingPeriod(StringBuilder("ABC"))) //輸出:ABC.P239:泛型的類型擦除,泛型之所以能限制容器或者方法實參的類型,是因為在編譯期做了校驗,但是到了運行是泛型類型會被擦出掉,也就是編譯期不會區(qū)分List<String>和List<Student>;不能判斷一個對象是否是List<String>,只能使用List<?>判斷該對象是否是List;在Kotlin中使用星號投影 :
if(value is List<*>){ ... }P241:Kotlin中內(nèi)聯(lián)函數(shù)的類型形參能夠被實化,意味著可以在運行時引用實際的類型實參。把函數(shù)聲明成inline并且用relified標(biāo)記類型參數(shù):
inline fun <reified T> isA(value:Any) = value is T >>>println(isA<String>("abc")) //輸出:true注意,帶relified類型參數(shù)的inline函數(shù)不能在java代碼中調(diào)用。
P244:使用實化類型參數(shù)代替類引用(class),如Activity中的startActivity函數(shù):
inline fun<relified T:Activity> Context.startActivity() {val intent = Intent(this,T::class.java)startActivity(intent) } >>>startActivity<DetailActivity>()P246:變型描述擁有相同基礎(chǔ)類型和不同類型實參的類型之間是如何關(guān)聯(lián)的(如List和List);當(dāng)一個可變字符串列表(MutableList)傳遞給一個期望Any對象列表的函數(shù)是否安全,取決于該字符串列表中的元素是否可變,如果是可變的,意味著列表中的元素類型可能不一致,則此時它是不安全的,編譯器會禁止編譯通過。
P248:協(xié)變:保留子類型化關(guān)系。如果Cat是Animal的子類型,那么如果List也是List的子類型,我們說子類型化被保留了;類型參數(shù)T上用關(guān)鍵字out修飾有兩層含義:
需要注意,位置規(guī)則只覆蓋了類外部可見的(public、protected和internal)API。私有方法的參數(shù)既不在in位置也不在out位置。in和out有點類似于java中的<? extend T>和<? super T>指定類型的上、下界限。
P253:
P256:可以為類型參數(shù)指定in、out來限制其為消費(可寫)、生產(chǎn)(只讀)。
P257:星號投射類似于java中的MyType<?>,你不知道里面存的是什么類型,所以不能往里存數(shù)據(jù),但是你可以往外取東西,因為里面的元素總是Any?的子類型。
P264:Kotlin中注解指定實參的語法和Java有所不同
P274:在Kotlin中使用反射,有兩種反射API,一種是標(biāo)準(zhǔn)的Java反射,定義在java.lang.reflect;第二種是Kotlin反射API,定義在kotlin.reflect中,Kotlin反射API被打包成獨立的jar文件,kotlin-reflect.jar,需要自己添加依賴導(dǎo)入進(jìn)來。在Kotlin中使用反射需要先使用javaClass獲取它的Java類,然后再通過.kotlin擴(kuò)展屬性,完成從Java到Kotlin的過渡。
val child = Child("Lucy") val kClass = child.javaClass.kotlin println(kClass.simpleName) //輸出:Child kClass.memberProperties.forEach{ println(it.name) } //輸出:nameP293:Kotlin的DSL(領(lǐng)域特定語言,專注在特定任務(wù)或領(lǐng)域上,并放棄與該領(lǐng)域無關(guān)的功能,如SQL)是完全靜態(tài)類型的,就像語言的其他功能一樣。這意味著靜態(tài)類型的所有優(yōu)勢,比如編譯時錯誤的檢測,以及更好的IDE支持,在你的API上使用DSL模式時仍然有效。
299:帶接收者的lambda是Kotlin的一個強(qiáng)大特性,它可以讓你使用一個結(jié)構(gòu)來構(gòu)建API,擁有結(jié)構(gòu)是區(qū)分DSL和普通API的關(guān)鍵特征。帶接收者的lambda格式:
String.(Int, Int) -> Unit;String為接收者類型,(Int, Int)為參數(shù)類型
fun buildString(builderAction:StringBuilder.()-> Unit):String {val sb = StringBuilder()sb.builderAction()return sb.toString() } val s2 = buildString {this.append("Hello")append("World") }當(dāng)你將一個普通函數(shù)類型轉(zhuǎn)換為擴(kuò)展函數(shù)類型時,其調(diào)用方式也發(fā)生了變化。想調(diào)用一個擴(kuò)展函數(shù)那樣調(diào)用lambda,而不是將對象作為參數(shù)傳遞給lambda。
val appendExcl :StringBuilder.() -> Unit = {this.append("!")} val s3 = StringBuilder("Hi") s3.appendExcl() println(s3) //輸出:Hi!可以看到這里的帶接收者的Lambda表達(dá)式,有點像一個匿名的擴(kuò)展函數(shù),且該匿名擴(kuò)展函數(shù)的對象時調(diào)用者自己
P310:invoke約定允許把自定義類型的對象當(dāng)做函數(shù)一樣調(diào)用。你已經(jīng)見過函數(shù)類型的對象,它們可以作為函數(shù)調(diào)用;使用invoke約定,也可以定義支持同樣語法的對象。get是我討論過的約定之一,它允許你使用下標(biāo)運算符來訪問一個對象。
class G(val g:String) {operator fun invoke(name:String) {println("$g,$name!")} } G("x")("w") //輸出:x,w!P311:Lambda除非是內(nèi)聯(lián)的,都是被編譯成實現(xiàn)了函數(shù)式接口(Function1等)的類,而這些接口定義了具有對應(yīng)數(shù)量參數(shù)的invoke方法。
P312:將lambda轉(zhuǎn)換成一個實現(xiàn)了函數(shù)類型接口的類,并重寫接口的invoke方法;是進(jìn)行重構(gòu)的一種方式。這種方法的優(yōu)點是從lambda函數(shù)體重抽取的方法的作用域被金可能縮小了。
data class Dog(val name:String,val color:String,val height:Int)class GoodDogPredicate():(Dog) -> Boolean {override fun invoke(dog: Dog): Boolean {return dog.isGoodColor() && dog.isGoodHeight()}private fun Dog.isGoodColor():Boolean {return color == "White"}private fun Dog.isGoodHeight():Boolean {return height < 50} }val dog1 = Dog("Tom","Yellow",40) val dog2 = Dog("Yame","White",40) val dog3 = Dog("Petty","White",100) val predicate = GoodDogPredicate() for(d in listOf(dog1,dog2,dog3).filter(predicate)) {println(d.name + " is a good dog!") //Yame is a good dog }總結(jié)
以上是生活随笔為你收集整理的读书笔记『Kotlin实战』的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最小单片机系统
- 下一篇: 计算机网络三大总线,计算机总线分为哪三种