当前位置: 首页 > article >正文

Kotlin语言基础笔记

       Kotlin是一门非常方便的开发语言,它的语法糖有很多,要想要很熟练的掌握kotlin语言,只有不断地使用kotlin写代码,从而达到量到质的一个改变。本文也只是介绍其中的一点内容,内容很松散,有些知识点需要自己动手去写,去实现才能真正体会其中的魅力。

1 高阶函数

1.1 Lambda表达式

分析高阶函数的基础是lambda表达式,先看一下常见的Lambda表达式的使用方式。

fun main() {

    // () -> Unit    空参函数  并且 没有返回值  函数名=method01

    // TODO 定义没有问题,调用不行
    /*var method01 : () -> Unit
    method01() // 不能调用  没有具体的实现

    var method02 : (Int, Int) -> Int
    method02(9, 9)

    var method03: (String, Double) -> Any?
    method03("Derry", 543354.4)

    var method04 : (Int, Double, Long, String ? ) -> Boolean
    method04(1, 545, 3543, null)

    var method05 : (Int, Int) -> Int
    method05(9, 9)*/

    // : (形参类型)
    // = {具体详情}

    // TODO 定义没有问题,调用OK ,因为有实现了
    var m06 : (Int, Int) -> Int = {number1, number2 -> number1 + number2}
    println("m06:${m06(9, 9)}")

    var m07 = { number1: Int , number2: Int -> number1.toDouble() + number2.toDouble()}
    println("m07:${m07(100, 100)}")

    var m08 : (String, String) -> Unit = {aString, bString -> println("a:$aString,  b:$bString")}
    m08("李元霸", "王五")

    var m09 : (String) -> String = {str -> str}
    println("m09:${m09("降龙十八掌")}")

    var m10 : (Int) -> Unit = {
        when(it) {
            1 -> println("你是一")
            in 20..30 -> println("你是 二十 到 三十")
            else -> println("其他的数字")
        }
    }
    m10(29)

    var m11 : (Int, Int, Int) -> Unit = { n1, n2, n3 ->
        println("n1:$n1, n2:$n2, n3:$n3")
    }
    m11(29,22,33)

    var m12 = { println("我就是m12函数,我就是我") }
    m12()

    val m13 = {sex: Char -> if (sex == 'M') "代表是男的" else "代表是女的"}
    println("m13:${m13('M')}")

    // 覆盖操作
    var m14 = {number: Int -> println("我就是m14  我的值: $number")}
    m14 = {println("覆盖  我的值: $it")}
    m14(99)

    // 需求:我想打印, 并且,我还想返回值,就是 我什么都想要
    var m15 = { number: Int -> println("我想打印: $number")
        number + 1000000
    }
    println("m15:${m15(88)}")
}

代码中的注释有对应的解释,此处我们不做过多的赘述,上面一共展示了15中Lambda表达式的使用方式,其实总结下来就2种形式:

// : (形参类型)
// = {具体详情}

对于Lambda表达式,至于说到底什么是Lambda表达式,其实我理解他就是一种规则,允许在编程过程中使用的一种规则。说穿了没有什么高深的东西,就是多多练习使用后熟能生巧的一个过程,这里只介绍这种语法糖即可。

1.2 扩展函数

fun main() {
    val stu = Student()
    stu.add(100, 200)

    // KT本来就有
    val file = File("///")
    file.readText()
    file.show()
}

// 扩展 函数
fun Student.add(n1: Int, n2: Int) {
    println("结果:${n1 + n2}")
}

fun Student.show() {
    println("Student show")
}

// 给 java File 增加 扩展函数
fun File.show() {
    println("给 java File 增加 扩展函数")
}

扩展函数可以理解为在外部对已有的类添加函数,什么意思呢,说穿了就是不想改动原来的类,但是呢又想对类的功能进行扩展,保持了原有的实现,然后又扩展了一项功能,使得其他的该类的变量都能够进行使用,这就是扩展函数的核心。

1.3 高阶函数

高阶函数的理解:如果在函数上用到了Lambda表达式,那该函数就属于高阶函数。

fun main() {
    show(true) {
        // println(it)
        'M'
    }
}

// TODO  loginMethod:(Boolean)->Unit

fun loginMethod(b: Boolean) : Unit {

}

// loginMethod 方法名
// (Boolean)方法的那个括号
// -> 方法体 干活
// Unit == void

fun show(isLogin: Boolean, loginMethod:(Boolean)->Char) {
    if (isLogin) {
        println("登录成功")
        val r = loginMethod(true)
        println(r)
    } else {
        println("登录失败")
        loginMethod(false)
    }
}

上面简单的举了一个扩展函数的例子,具体的解释代码中已经注释了,其实高阶函数,就是在参数中定义了一个Lambda表达式。

其实我们平时使用的let、run、with、apply、also都是一些高阶的扩展函数,我们来分析一下具体的实现,感受一下高阶函数的魅力:

@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.also(block: (T) -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block(this)
    return this
}

@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, Invoc ationKind.EXACTLY_ONCE)
    }
    return block(this)
}

@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}

@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

总结:

also let :

        使用的参数传递调用者对象的方式,也就是将调用者的对象以参数的形式传入到高阶函数中,然后通过"调用者对象参数.方法"的方式调用调用者对象中的方法。

        返回值不一样,also的返回值是调用者对象本身,let的返回值是高阶函数实现体的最后一行代码的返回值类型。

apply、with、run:

        都是通过对调用者对象增加匿名函数的方式实现,这样做的好处是在高阶函数的具体实现中全局的增加了一个this对象,随时都可以直接调用调用者对象中的其他方法,不需要使用"this.方法"的方式。
        返回值不一样,apply返回的是调用者本身,with run返回的是高阶函数的最后一行代码的返回类型。

1.4 Kt关键字in out

此处多提一下,kotlin中有2个关键字:in和out,其实这2个关键字比较好理解,只要你理解了之前分析的泛型中的extend和super关键词,那么我们肯定就能理解,来看一下Java中泛型的读取模式:
 

    // 泛型读取模式
    void test01() {

        // ? extends FuClass  == 只能获取,不能修改
        List<? extends FuClass> list = new ArrayList<ZiClass>();

        // 不能修改
        /*list.add(fuClass);
        list.add(ziClass);*/

        // 能获取
        FuClass fuClass = list.get(0);

        // TODO  =============================================


        // ? super ZiClass == 只能修改,不能获取
        List<? super ZiClass> list2 = new ArrayList<FuClass>();

        // 能添加
        list2.add(ziClass);

        // 不能获取
        // ZiClass ziClass = list2.get(0);
    }

extend是只能获取不能修改,super是只能修改不能获取。那么kotlin中extend对应的out,super对应的in。

fun test01() {
    // out 只能取,不能修改   == ? extends FuClass
    val list: MutableList<out FuClass> = ArrayList<ZiClass>()

    // in 只能修改(存), 不能获取   === ? super ZiClass
    val list2: MutableList<in ZiClass> = ArrayList<FuClass>()
}
// 这个类,就是只能获取,不能修改了
// 声明的时候加入  一劳永逸了<in T>
class Worker <out T> {

    // 能获取
    fun getData() : T? = null

    // 不能修改
    /*fun setData(data: T) {

    }

    fun addData(data: T) {

    }*/
}
// 这个类,就是只能修改, 不能获取
// 声明的时候加入  一劳永逸了<in T>
class Student<in T> {

   /*fun a(list: MutableList<in T>) {

    }

    fun a2(list: MutableList<in T>) {

    }

    fun a3(list: MutableList<in T>) {

    }

    fun a4(list: MutableList<in T>) {

    }

    fun a5(list: MutableList<in T>) {

    }*/

    fun setData(data: T) {}

    fun addData(data: T) {}

    // 不能获取
    // fun getData() : T
}

2 协程

2.1 协程的使用

协程的使用主要是2个方式runBlocking和GlobalScope.launch的方式,具体看一下实现

fun click3(view: View) = runBlocking {
	// TODO 完成这种  异步线程  和  主线程  的切换,  这个需求:之前我们用RxJava实现过了哦
	// 1.注册耗时操作
	// 2.注册耗时操作完成后,更新注册UI
	// 3.登录耗时操作
	// 4.登录耗时操作完成后,更新登录UI

	// main
	launch {

		val pro = ProgressDialog(this@MainActivity)
		pro.setMessage("正在执行中...")
		pro.show()

		withContext(Dispatchers.IO) {
			// 1.注册耗时操作  异步
			Log.d("click3", "1.注册耗时操作: ${Thread.currentThread().name}")
			Thread.sleep(2000)
		}

		// 2.注册耗时操作完成后,更新注册UI  main
		Log.d("click3", "2.注册耗时操作完成后,更新注册UI: ${Thread.currentThread().name}")

		withContext(Dispatchers.IO) {
			// 3.登录耗时操作  异步
			Log.d("click3", "3.登录耗时操作: ${Thread.currentThread().name}")
			Thread.sleep(3000)
		}

		// 4.登录耗时操作完成后,更新登录UI
		Log.d("click3", "4.登录耗时操作完成后,更新登录UI: ${Thread.currentThread().name}")

		// pro.dismiss()
	}

}

runBlocking平时的开发中一般是不用的,一般是在测试过程中使用,因为runBlocking是阻塞式的。

// 非阻塞
fun click4(view: View)  {
	// TODO 完成这种  异步线程  和  主线程  的切换,  这个需求:之前我们用RxJava实现过了哦
	// 1.注册耗时操作
	// 2.注册耗时操作完成后,更新注册UI
	// 3.登录耗时操作
	// 4.登录耗时操作完成后,更新登录UI

	// main
	GlobalScope.launch (Dispatchers.Main) {

		val pro = ProgressDialog(this@MainActivity)
		pro.setMessage("正在执行中...")
		pro.show()

		withContext(Dispatchers.IO) {
			// 1.注册耗时操作  异步
			Log.d("click3", "1.注册耗时操作: ${Thread.currentThread().name}")
			Thread.sleep(2000)
		}

		// 2.注册耗时操作完成后,更新注册UI  main
		Log.d("click3", "2.注册耗时操作完成后,更新注册UI: ${Thread.currentThread().name}")
		textView.text = "注册成功,你可以去登录了"
		pro.setMessage(textView.text.toString())

		withContext(Dispatchers.IO) {
			// 3.登录耗时操作  异步
			Log.d("click3", "3.登录耗时操作: ${Thread.currentThread().name}")
			Thread.sleep(3000)
		}

		// 4.登录耗时操作完成后,更新登录UI
		Log.d("click3", "4.登录耗时操作完成后,更新登录UI: ${Thread.currentThread().name}")
		textView.text = "登录成功,欢迎回来"
		pro.setMessage(textView.text.toString())

		pro.dismiss()
	}

}

2.2 协程的原理

至于原理,有一篇博客讲解的很好,大家可以参考:https://www.jianshu.com/u/a324daa6fa19


http://www.kler.cn/a/588877.html

相关文章:

  • coding ability 展开第三幕(滑动指针——基础篇)超详细!!!!
  • 【干货】Docker 在自动化测试和性能测试中的应用
  • Vue.js 中 class 和 style 绑定的全面解析
  • JVM的各种细节
  • visual studio code C++开发基础配置
  • 【商城实战(37)】Spring Boot配置优化:解锁高效商城开发密码
  • 谷歌推出 Gemini Robotics:让机器人像人类一样思考与行动
  • 探索ima.copilot:个人知识库搭建的AI新利器
  • 【机器学习-基础知识】统计和贝叶斯推断
  • 2018年全国职业院校技能大赛高职组-计算机网络应用竞赛竞赛样题E卷
  • 【GOOGLE插件】chrome.runtime.sendNativeMessage与本地应用交互
  • Xinference大模型配置介绍并通过git-lfs、hf-mirror安装
  • 【Node.js入门笔记4---fs 目录操作】
  • 【华为OD-E卷 -121 消消乐游戏 100分(python、java、c++、js、c)】
  • 9种Python数据可视化方案,让财务数据焕发生命力
  • 基于Spring Boot的网上蛋糕售卖店管理系统的设计与实现(LW+源码+讲解)
  • 谷云科技RestCloud智能体搭建平台助力企业快速搭建AI Agent
  • spring boot连接clickhouse集群,实现故障节点自动切换
  • Python基于深度学习的多模态人脸情绪识别研究与实现
  • 【TCP】三次挥手,四次挥手详解--UDP和TCP协议详解