高級特性
1、解構
class User(var age:Int,var name:String){
//operator將一個函數標記爲重載一個操作符或者實現一個約定
operator fun component1() = age
operator fun component2() = name
}
fun main() {
var user = User(12,"aaa")
var (age,name) = user
}
在賦值的時候 調用component1和2這兩個方法賦值給第一個、第二個元素。
解構更常見於map:
fun main() {
var map = mapOf<String,String>("1" to "key1","2" to "key2")
for((k,v) in map){
println("key:$k,value:$v")
}
}
2、循環和集合操作符
五種循環語法:
fun main() {
for(i in 1..10){
println(i)
}
for(i in 1 until 10){
println(i)
}
for(i in 10 downTo 1){
println(i)
}
for(i in 1..10 step 2){
}
repeat(10){
println(it)
}
}
遍歷集合:
fun main() {
var list = arrayListOf<String>("a","b","c")
for(str in list){
println(str)
}
for((index,str) in list.withIndex()){
println("$index ,,, $str")
}
}
3、集合操作符:
fun main() {
var list = arrayListOf<Char>('a','b','c','d')
//返回符合條件的第一個
val a = list.map { it - 'a' }.filter { it > 0 }.find { it > 1 }
}
fun demo(){
var a = arrayOf("4","0","i","f","w","0","9")
var index = arrayOf(5,3,9,4,8,31,9,2,1,7)
index.filter {
it < a.size
}.map {
a[it]
}.reduce{
s , s1 -> "$s$s1"
}.also {
println(it)
}
}
filter就像過濾器一樣,篩選出符合條件的。map是可以改變返回的數據類型的,原先返回值是int,現在返回值是String。reduce可以取出兩個拼接字符串,最後also輸出結果。
常用操作符:
4、作用域函數
fun main() {
val user = User("zhangsan")
//let和run都會返回閉包的執行結果,區別在於let閉包有參數,而run閉包沒有參數
var letResult:String = user.let { user:User -> "let::${user.javaClass}" }
println(letResult)
var runResult:String = user.run { "run::${this.javaClass}" }
//also與apply都不返回閉包的執行結果,區別在於also有閉包參數,而apply沒有閉包參數
user.also {
println("also::${it.javaClass}")
}
user.apply {
println("apply::${this.javaClass}")
}
//takeIf的閉包返回一個判斷結果,爲false時,takeIf函數會返回null
//takeUnless 與 takeIf剛好相反,閉包的判斷結果,爲true時,函數返回null
user.takeIf { it.name.length > 0 }?.also { println("name:${it.name}") } ?: println("name:null")
user.takeUnless { it.name.length > 0 }?.also { println("name:null") } ?: print("name:${user.name}")
//重複執行當前閉包
repeat(5){
println(user.name)
print(it)
}
//with比較特殊,是一個頂級函數,與下面的apply類似
with(user){
this.name = "with"
}
//user.apply { this.name = "with" }
5、中綴表達式
fun main() {
for(i in 1..100 step 20){
println(i)
}
}
//實際上這個代碼在編譯後就變成了一個方法,來幫我們實現這樣的一種簡寫,這個就是運算符重載
//通過operator實現,rangeTo的方法
手寫一箇中綴表達式:
fun main() {
println(5 vs 6)
}
sealed class CompareResult{
object LESS:CompareResult(){
override fun toString(): String {
return "小於"
}
}
object MORE:CompareResult(){
override fun toString(): String {
return "大於"
}
}
object EQUAL:CompareResult(){
override fun toString(): String {
return "等於"
}
}
}
infix fun Int.vs(num:Int):CompareResult =
if(this - num < 0){
CompareResult.LESS
}else if(this - num > 0){
CompareResult.MORE
}else{
CompareResult.EQUAL
}
用infix關鍵字定義運算符重載函數
6、DSL(領域專用語言:json、xml..巴拉巴拉)
自己感興趣可以查一查。
7、val和var的本質區別
var 對象實際上是擁有getter和setter方法的,val是沒有setter方法的,但是我們可以重寫get方法達到某種變得目的。
這個是var修飾得數據:
class demo{
var a:Int = 1
set(value){
field = value
}
get(){return field}
}
這裏面set得時候不可以用a=value,因爲只要用a=xx這個變量就會觸發set方法。就會一直遞歸造成棧溢出。
val修飾得數據:
class demo{
val a:Int = 1
get(){return field}
}
fun main() {
var demo:Demo = Demo()
println(demo.a)
demo.countAdd()
println(demo.a)
}
class Demo{
var count = 1;
val a:Int = 1
get(){return field + count}
fun countAdd(){
count++;
}
}
我們可以在get上面做手腳達到可變的目的。輸出2、3。如果我們真想用常量,可以試着用const val關鍵字。
const val b:Int = 1;
class Demo{
companion object {
const val a:Int = 1;
}
}
這個const只能修飾在object裏面,也就是我們的單例對象和類的外邊。const val只能修飾基本數據類型和String類型,在編譯期就可以知道類型的數據。
8、內聯noinline
kotlin規定:內部lambda是不允許中斷外部執行的。
而inline是可以的:
fun main() {
test {
print("aaaaa")
return
}
print("bbbbb")
}
inline fun test(l : () -> Unit){
l.invoke()
}
只會打印aaaaa,這是不行的。如果我們去掉inline呢?
fun main() {
test {
print("aaaaa")
return@test
}
print("bbbbb")
}
fun test(l : () -> Unit){
l.invoke()
}
kotlin就會讓我們return@test,表示執行完這個閉包,打印aaaaa、bbbbb。
fun main() {
test {
print("aaaaa")
return@test
print("ccccc")
}
print("bbbbb")
}
inline fun test(crossinline l : () -> Unit){
l.invoke()
}
如果我們想要有inline還得輸出aaaaa,bbbbb。就只能像上面這樣做了。
9、泛型
class Test<T> where T:Runnable{
fun add(t:T){
t.run()
}
}
聲明T必須是Runnable的一個子類。