在Kotlin中可以把一个对象赋值给多个变量,这种操作叫做解构说明
data class Boy(var age:Int,var name:String)var boy = Boy(35,"周杰伦")//下面这两种方式 都可以获得变了的值var(age,name) = boyvar(age1,name1) = boy
上面用关键字data修饰了class ,被称之为数据类,数据类之所以可以使用解构声明,是由于数据类比较特殊,我们可以在app/bulid/tmp/kotlin-calsses目录下,查看生成之后的代码java代码
public final data class Boy public constructor(age: kotlin.Int, name: kotlin.String) { public final var age: kotlin.Int public final var name: kotlin.String public final operator fun component1(): kotlin.Int { } public final operator fun component2(): kotlin.String { }}
而我们可以通过以下方式查看上面的data class 生成的字节码
其实就是 componet1方法 将age返回 ,component2将name返回,我们在通过上面Kotlin Bytecode区域的左上角DECOMPILE 可以查看kotlin翻译成的java代码实现
上面的componentN()函数就是解构的核心
自定义解构对于一个普通的类不具备解构的功能,除非像我们上面使用data来声明。但是一个自定义的普通的class我们还是可以手动声明operator fun componentN(){ } 方法的方式来实现解构的功能,我们将上面的Boy类的data修饰符去掉
class Boy(var age:Int,var name:String){ operator fun component1() = age operator fun component2() = name}
这样我们同样能够使用解构功能。像原来我们需要返回一个具体的Boy类型 然后通过boy.age的多个参数值的方式我们可以用下面的方法改写
fun getBoyInfo(): Boy { return Book(42, "Kobe") } val (age, name) = getBoyInfo() //这样也精简了代码
infix关键字infix关键字修饰的函数,在Kotlin中 就是允许 函数采用中缀表达式的形式去调用,中缀表达式的使用需要满足3个前提条件
必须是成员函数或者扩展函数函数只有一个参数参数不可能是可变参数或者默认参数像我们平时使用Kotlin中的map的时候 对map进行初始化的时候 可以这样
var map = mutableMapOf
其实 这里的 to 就是使用了 infix修饰了的一个扩展函数
public infix fun A.to(that: B): Pair = Pair(this, that)
其实我们也可以这样调用
但是AndroidStudio会提示我让我 使用 ‘to’ infix的形式,其实这种方法也没有什么特别之处,我觉得唯一的特别之处 就是我们的 代码更接近于人类的自然 语言,我们用下面的例子更加能够说明
class Person{ infix fun sayHelloTo(name : String){ println("你好 $name" ) } }
我们没有加infix修饰 就可能是下面的代码
var kobe = Person()kobe.sayHelloTo("周杰伦")
必须使用方法的调用,但是使用infix之后,我们可以用类似 中文语言的形式使用代码
kobe sayHelloTo "周杰伦"
是不是感觉很奇妙
扩展函数和扩展属性kotlin有一个特别好使用的的功能叫做扩展,你可以给已有的类去额外添加函数和属性,而且既不需要修改源码也不需要写子类,比如我们可以给Float 扩展一个dp属性
val Float.dp get() = TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, this, Resources.getSystem().displayMetrics )...//这里就可以直接使用了,val RADIUS = 200f.dp
这里我们就可以直接使用200f.dp 了 ,不需要我们平时使用写一个单独的utils类,写一个静态方法,然后每次调用的时候 都调用这个utils的静态方法,这样可以省略掉不少代码
同样的我们也可以给Float定义 dp函数,我们将上面的扩展属性修改为 扩展函数,
fun Float.dp() = TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, this, Resources.getSystem().displayMetrics )...//这里就可以直接使用了,val RADIUS = 200f.dp()
这样我们可以使用扩展函数的形式调用了,虽然这个dp的例子有些不恰当,但是我们也可以看到扩展函数或者扩展属性的魅力。
我们可以将我们的扩展函数 或者扩展属性直接写在kotlin文件中,然后在同module下面,我们所有的类种都可以访问到扩展函数或者扩展属性,例如下面,新建一个TimeUtils.kt的文件,不需要在这里文件中声明class文件,直接在里面编写kotlin扩展函数就行
这就是kotlin的Top-Level ,我们可以在其他任何地方使用这些扩展方法
Kotlin的高阶函数在Kotlin中,我们将参数有函数类型或者返回值是函数类型的函数,都叫做高阶函数。例如下面的函数
fun sum(num:Int,a:(Int)->Int,b:(Int)->Int):Int{ return a(num)+b(num)}
我们可以将sum函数看作高阶函数
调用的时候 我们可以按照下面的方式调用
var result = sum(3,{param1-> param1 +3} ,{param2->param2+4})
这里将上面的 函数类型的参数 写成了两个lambda的形式,我们也可以在函数sum函数中写匿名函数
sum(base, fun(i:Int):Int { return i+3 },fun (i:Int):Int { return i+4 })
这个其实与上面lambda的一种表现形式
还有另外一种写法 ,将函数作为一个对象来使用
fun fun1(i:Int):Int { return i+3 }fun fun2(i:Int):Int { return i+4 }fun sum(num:Int,a:(Int)->Int,b:(Int)->Int):Int{ return a(num)+b(num)}var base = 3var result = sum(base, ::fun1,::fun2)
这样使用和上面得到同样的效果
在官方的文档中 将 :: method 这种写法叫做函数引用 Function Reference 这里是官方的说法。但是更喜欢“扔物线”文章中的说法 ,函数加上两个冒号,就可以将函数变成一个对象。Kotlin 里「函数可以作为参数」这件事的本质,是函数在 Kotlin 里可以作为对象存在——因为只有对象才能被作为参数传递啊
有了函数对象这样一个概念,我们就可以将函数赋给一个变量
var base = 3var c = ::fun1var result = sum(base, c,::fun2)
当然我们可以将一个函数的定义 赋值给一个变量,然后将变量直接作为函数参数调用
var function1 = fun(i:Int):Int { return i+3 }fun fun2(i:Int):Int { return i+4 }var base = 3var result = sum(base, function1,::fun2)// 我们也可以这么调用function1(2)// fun2的另外一种调用方法(::fun2)(2) //实际上调用的是 (::fun2).invoke(2)
Lambda 表达式如果 Lambda 是函数的最后一个参数,你可以把 Lambda 写在括号的外面:
view.setonClickListener() { v: View -> //doSomething}
而如果 Lambda 是函数唯一的参数,你还可以直接把括号去了:
view.setonClickListener { v: View -> //doSomething}
另外,如果这个 Lambda 是单参数的,它的这个参数也省略掉不写:
view.setonClickListener { //doSomething}
哎呦,不错额,单参数的时候只要不用这个参数就可以直接不写了。其实就算用,也可以不写,因为 Kotlin 的 Lambda 对于省略的唯一参数有默认的名字:it:
view.setonClickListener { // doSomething it.setVisibility(GONE)}