Kotlin的一些特性记录
Posted 做一个苦行僧
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin的一些特性记录相关的知识,希望对你有一定的参考价值。
Kotlin的解构
在Kotlin中可以把一个对象赋值给多个变量,这种操作叫做解构说明
data class Boy(var age:Int,var name:String)
var boy = Boy(35,"周杰伦")
//下面这两种方式 都可以获得变了的值
var(age,name) = boy
var(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 /* compiled code */
public final var name: kotlin.String /* compiled code */
public final operator fun component1(): kotlin.Int /* compiled code */
public final operator fun component2(): kotlin.String /* compiled code */
而我们可以通过以下方式查看上面的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<String,String>("age" to "12","name" to "周杰伦")
其实 这里的 to 就是使用了 infix修饰了的一个扩展函数
public infix fun <A, B> A.to(that: B): Pair<A, B> = 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 = 3
var result = sum(base, ::fun1,::fun2)
这样使用和上面得到同样的效果
在官方的文档中 将 :: method 这种写法叫做函数引用 Function Reference 这里是官方的说法。但是更喜欢“扔物线”文章中的说法 ,函数加上两个冒号,就可以将函数变成一个对象。Kotlin 里「函数可以作为参数」这件事的本质,是函数在 Kotlin 里可以作为对象存在——因为只有对象才能被作为参数传递啊
有了函数对象这样一个概念,我们就可以将函数赋给一个变量
var base = 3
var c = ::fun1
var result = sum(base, c,::fun2)
当然我们可以将一个函数的定义 赋值给一个变量,然后将变量直接作为函数参数调用
var function1 = fun(i:Int):Int return i+3
fun fun2(i:Int):Int return i+4
var base = 3
var 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)
带有接收者的函数字面值
以上是关于Kotlin的一些特性记录的主要内容,如果未能解决你的问题,请参考以下文章