Kotlin进阶

data class:

data class为“数据类”;同时会⽣成以下方法:

  • toString()
  • hashCode()
  • equals()
  • copy() (会返回一个新的对象)
  • componentN() ...

解构:

定义为data class后,可以把⼀个对象的构造函数参数值「解构」成多个变量

在解构变量时,所在对象对象的构造器函数里必需要持有相同参数值
data class CodeView(var code: String, var message: String, var body: String) {
    fun test() {
        val (code1, message1, body1) = CodeView("1", "2", "3")
    }
}

 

Elvis 操作符:

可以通过 ?: 的操作来简化 if null 的操作
 
// lesson.date 为空时使⽤默认值
val date = lesson.date?: "⽇⽇期待定"
// lesson.state 为空时提前返回函数
val state = lesson.state?: return
// lesson.content 为空时抛出异常
val content = lesson.content ?: throw
IllegalArgumentException("content expected")

下面示例代码中,code如果是null,就赋值给value"111",否则就赋值code
class CodeView {
    var code: String? = null
    var value: String = code ?: "111"
}

相等性:

  • == 结构相等 (调⽤ equals() ⽐较 )
  • === 引⽤(地址值)相等

when 操作符:

when 表达式可以接受返回值,多个分⽀相同的处理⽅式可以放在⼀起,⽤逗号分隔。
val colorRes = when (lesson.state) {
 Lesson.State.PLAYBACK, null -> R.color.playback
 Lesson.State.LIVE -> R.color.live
 Lesson.State.WAIT -> R.color.wait
}
when 表达式可以⽤来取代 if-else-if 链。如果when的括号内不提供参数,所有的分⽀条件都是布尔表达式
 
val colorRes = when {
 (lesson.state == Lesson.State.PLAYBACK) ->
R.color.playback
 (lesson.state == null) -> R.color.playback
 (lesson.state == Lesson.State.LIVE) -> R.color.live
 (lesson.state == Lesson.State.WAIT) -> R.color.wait
 else -> R.color.playback
}

operator:

通过 operator 修饰「特定函数名」的函数,例如 plus get ,可以达到重载运算符的效果。
 

 

lambda:

如果函数的最后⼀个参数是 lambda ,那么 lambda 表达式可以放在圆括号之外:
 
lessons.forEach(){ lesson : Lesson ->
 // ...
}
如果你的函数传⼊参数只有⼀个 lambda 的话,那么⼩括号可以省略的:
lessons.forEach { lesson : Lesson ->
 // ...
}
如果 lambda  表达式里只有⼀个参数名,那么可以省略参数名,通过编译器提供的隐式  it 来访问
 
lessons.forEach { // it
 // ...
}

 

嵌套函数:

在函数中继续声明函数。

  • 内部函数可以访问外部函数的参数
  • 每次调⽤时,会生成一个额外的对象;所以在确实可以提高代码可读性的情况下使用,否则最好不要用。
fun func(){
 fun innerFunc(){
 
   }
 }

函数简化:

可以通过符号 = 简化原本直接 return 的函数

fun get(key :String) = SP.getString(key,null)

示例未简化的时候:
    fun test(): String {
        return ""
    }
示例简化的时候:
fun test(): String= ""
因为有类型推断,所以返回值也可以简化
fun test() = ""

函数参数默认值:

可以通过函数参数默认值来代替 Java 的函数重载

// 使⽤ @JvmOverloads 对 Java 暴露重载函数
@JvmOverloads
fun toast(text: CharSequence, duration: Int =
Toast.LENGTH_SHORT) {
 Toast.makeText(this, text, duration).show()
}

上面这个方法在调用时,如果传入一个参数,则第二个默认值生效,如果传入两个参数,第二个默认值失效。
@JvmOverloads注解是对Java暴露重载函数,如果不加该注解,Java调用该函数时必须要传入两个参数。

扩展函数:

  • 扩展函数可以为任何类添加上⼀个函数,从⽽代替⼯具类
  • 扩展函数和成员函数相同时,成员函数优先被调⽤
  • 扩展函数必须是静态函数(顶层函数或者@JvmStatic注解的函数
下面示例是顶层函数
package com.example.myapplication.kt
fun Float.dp2px(): Float {
    return 1f
}
object CodeView {
    
}

调用
6f.dp2px()

函数类型:

函数类型主要分为两步

  • 调用函数的时候在参数内传入函数
  • 函数的实现体在参数内接收一个函数 

函数类型由「传⼊参数类型」和「返回值类型」组成,⽤「 -> 」连接,传⼊参数需要⽤「 () 」,如果返回值为 Unit 不能省略 函数类型实际是⼀个接⼝,我们传递函数的时候可以通过「 ::函数名 ,或者「匿名函数」或者使⽤ 「 lambda

class CodeView {
    fun codeViewRun(codeView: (CodeView) -> Unit) {

    }
}

fun main() {
    val codeView = CodeView()
    codeView.codeViewRun(::run1)
}

fun run1(codeView: CodeView) {

}

 

 

内联函数:

  • 内联函数配合「函数类型」,可以减少「函数类型」⽣成的对象
  • 使⽤ inline 关键字声明的函数是「内联函数」,在「编译时」会将「内联函数」中的函数体直接插⼊到调⽤处。
object CodeView {
    inline fun test() {
        var value = ""
    }
    fun code() {
        test()
    }
}

上面代码,编译器经过编译后,生成的代码是:
object CodeView {
    fun code() {
       var value = ""
    }
}

因为内联函数是直接将函数体里的代码拷贝到调用处的,所以在内联函数里应该避免具体实现的代码,而应该存放一些已经实现逻辑的函数体调用,经过内联函数的包装后调用,在提高阅读的前提下,同时减少调用栈。
具体化的类型参数:
因为内联函数的存在,我们可以通过配合 inline + reified 达到「真泛型」的效果
在未使用具体化类型参数的时候是这样声明和调用的
class CodeView {
    fun <T> create(clazz: Class<T>) {

    }
    fun test() {
        create(CodeView::class.java)
    }
}
使用具体化类型参数是这样声明和调用的
class CodeView {
    inline fun <reified T> create() {
        var aClass = T::class.java
    }

    fun test() {
        create<CodeView>()
    }
}
 
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页