Kotlin基本用法《四》-又想到了一些

补充一些杂七杂八有用的东西

Kotlin 中的 runletwithapply 都是作用域函数 (Scope Functions),它们的核心作用是创建一个临时作用域,简化代码并增强可读性 。虽然功能相似,但适用场景不同,主要区别在于接收者(this/it)的使用方式返回值

函数 接收者引用 返回值 适用场景
let it(默认) lambda 最后一行结果 处理非空对象、转换对象、限定局部变量作用域
run this lambda 最后一行结果 组合对象初始化与结果计算、替代临时变量
with this lambda 最后一行结果 对同一对象执行多操作(无空安全检查)
apply this 调用者本身(接收者) 对象配置初始化(如设置属性)、链式调用

let

特点

  • it 引用接收者(可自定义名称)
  • 返回 lambda 最后一行的结果
  • 常用 ?.let 形式处理非空对象(空安全
rust 复制代码
val str: String? = "Hello"

// 仅当 str 非空时执行(避免手动写 if (str != null))
str?.let {
    println("长度:${it.length}")  // it 指代 str 的非空值
    it.uppercase()  // 最后一行作为返回值
} ?: "默认值"  // 可配合 ?: 处理空情况

// 输出:长度:5,返回 "HELLO"
"默认值"  // 可配合 ?: 处理空情况

let 用法,默认 it 就指代这个str,当然你也可以不用it,改成ele, 这个随你

rust 复制代码
str?.let { ele ->
   println("长度:${ele.length}")  // it 指代 str 的非空值
    ele.uppercase()  // 最后一行作为返回值 
}
java 复制代码
// 临时变量仅在 let 作用域内可见
val result = "test".let { temp ->
    val upper = temp.uppercase()
    upper + "123"
}
println(result)  // 输出:TEST123

run

  • 特点

  • this 引用接收者(可省略)

  • 返回 lambda 最后一行的结果

  • 有两种用法:对象.run { ... } 或独立 run { ... }

kotlin 复制代码
data class User(var name: String, var age: Int)

val user = User("Alice", 20)

// 对 user 执行多步操作,并返回计算结果
val isAdult = user.run {
    name = "Alicia"  // 省略 this,直接访问属性
    age += 5
    age >= 18  // 返回布尔值
}

println(user)  // 输出:User(name=Alicia, age=25)
println(isAdult)  // 输出:true

run 用法,默认 就指代自身,即user, 形成一个闭包区域,节省代码,你想想,如果没有闭包 如果user属性很多,那么我就会这么写

ini 复制代码
user.name ="Alicia" 
user.age =25
user.name ="Alicia" 
uesr.height = 170
user.weight = 80

如果有闭包,那么就是

ini 复制代码
user?.run {
    name ="Alicia" 
    age =25
    height =180
    weight = 80
}

额外用法

ini 复制代码
// 独立 run 创建局部作用域,避免变量污染
val total = run {
    val a = 10
    val b = 20
    a + b
}
println(total)  // 输出:30

with:对同一对象执行多操作

  • 特点

    • 第一个参数是接收者,用 this 引用(可省略)
    • 返回 lambda 最后一行的结果
    • 无空安全检查(接收者为 null 时会崩溃)

因为它的特点,这个我用的比较少,没有空安全检查。

scss 复制代码
val list = mutableListOf<String>()

// 对 list 执行一系列操作
val size = with(list) {
    add("Apple")
    add("Banana")
    add("Cherry")
    size  // 返回集合大小
}

println(list)  // 输出:[Apple, Banana, Cherry]
println(size)  // 输出:3

如果list是这么声明的话 即 var list: mutableListOf? = null 那么with(list)就会崩 若接收者可能为 null,需先判断非空:

javascript 复制代码
val str: String? = "test"
if (str != null) {
    with(str) {
        println(length)  // 安全调用,需先确保 str 非空
    }
}

apply:对象配置与初始化

特点

  • this 引用接收者(可省略)
  • 返回接收者本身(便于链式调用)
  • 常用于对象创建后设置属性(替代 builder 模式)

经典用法:

scss 复制代码
// 创建并配置 TextView(Android 场景)
val textView = TextView(context).apply {
    text = "Hello"
    textSize = 16f
    setTextColor(Color.BLACK)
    setPadding(10, 10, 10, 10)
}
// apply 返回 textView 本身,可直接使用
layout.addView(textView)

如何决定用哪个?

  1. 处理非空对象let?.let 是经典用法)
  2. 对象配置初始化apply(返回自身,适合链式设置)
  3. 对同一对象执行多操作并返回结果with(非空对象)或 run(可空对象用 ?.run
  4. 组合初始化与计算run(尤其是需要返回计算结果时)
  5. 创建局部作用域let 或独立 run

by lazy

在 Kotlin 中,by lazy 是一种延迟初始化 机制,用于在首次访问变量时才初始化其值,而不是在变量声明时就初始化。这种方式可以优化性能(避免提前创建资源),尤其适合初始化成本较高的对象(如大型数据结构、网络连接等)。

说白了就是类似懒加载 但是要注意

  • by lazy 只能用于不可变变量(val ,因为初始化后值不会再改变。
  • 初始化逻辑(lambda 表达式)仅在变量首次被访问时执行一次,后续访问直接返回已初始化的值。

它只能是val 类型的

lateinit关键字

by lazylateinit 都用于延迟初始化,但适用场景不同:

特性 by lazy lateinit var
变量类型 只能用于 val(不可变) 只能用于 var(可变)
初始化时机 首次访问时自动执行初始化逻辑 需手动调用初始化代码(无自动逻辑)
适用场景 初始化逻辑明确(可在 lambda 中写) 初始化逻辑复杂(需外部调用)
类型限制 无(基本类型、对象都可) 只能用于非空对象类型(不能是基本类型)
kotlin 复制代码
// by lazy:自动执行初始化逻辑
val lazyValue by lazy { "自动初始化的值" }

// lateinit:需手动初始化
lateinit var lateValue: String
fun initLateValue() {
    lateValue = "手动初始化的值"  // 必须在使用前调用
}

fun main() {
    println(lazyValue)  // 自动初始化
    initLateValue()     // 手动初始化
    println(lateValue)
}

lateinit 声明的对象,编译器不会检测它是否为空,默认coder会让它不为空,那么这就埋下了隐患,如果最后运行的时候,这个属性为空,那么还是会崩溃

object

object 关键字,可以直接声明单例类,再也不用像java 一样,什么懒汉,饿汉式了,双重校验了。其实这个object,就是类似java中静态方法式声明单例。

kotlin 复制代码
object DisplayUtils { 
    fun px2dip(context: Context, pxValue: Float): Int {
        val scale = context.resources.displayMetrics.density
        return (pxValue / scale + RATE).toInt()
    }
}

但是在kotlin 中,object还有一个作用,

kotlin 复制代码
OSSUpload.with(context)
    .projectName("user_pic")
    .city(city)
    .clearTime(OSSClearTime.oneMonth)
    .uris(uploadUris)
    .upload(object : OSSUploadListener {
        override fun progress(i: Int, l: Long, l1: Long) {
            listener?.onProgress()
        }

        override fun success(ossUploadResult: OSSUploadResult) {
            val urlList = ossUploadResult.urls.stream()
                .map { ossUploadUrl: OSSUploadUrl -> ossUploadUrl.url }
                .collect(Collectors.toList())

          
            listener?.onSuccess(urlList as ArrayList<String>)
        }

        override fun error(s: String, s1: String) {
            listener?.onFail(s)
            
        }
    })

能看出来么,就是声明一个匿名内部类 object : OSSUploadListener {}

说了这么多,听懂了啵,可以尝试用起来,为什么不用,tell me why baby

相关推荐
大王派来巡山的小旋风4 小时前
Kotlin基本用法三
android·kotlin
大王派来巡山的小旋风6 小时前
Kotlin基本用法之集合(一)
android·程序员·kotlin
一条上岸小咸鱼7 小时前
Kotlin 基本数据类型(四):String
android·前端·kotlin
常利兵13 小时前
Kotlin作用域函数全解:run/with/apply/let/also与this/it的魔法对决
android·开发语言·kotlin
幼稚园的山代王13 小时前
Kotlin-基础语法练习一
android·开发语言·kotlin
一条上岸小咸鱼1 天前
Kotlin 基本数据类型(三):Booleans、Characters
android·前端·kotlin
alexhilton1 天前
深入浅出着色器:极坐标系与炫酷环形进度条
android·kotlin·android jetpack
一条上岸小咸鱼1 天前
Kotlin 基本数据类型(一):Numbers
android·前端·kotlin
一条上岸小咸鱼2 天前
Kotlin 基本数据类型(一):概述及分类
android·kotlin