写过 Java 的同学对 a = b = c = 10 这种写法应该不陌生,赋值在 Java 中是一个表达式,会把右边的值返回出来,于是可以一路串下去。但把这段代码原样搬到 Kotlin 里,编译器会直接给你一个提示:赋值操作不是表达式。这篇文章就来聊聊为什么 Kotlin 要这样设计,以及在 Kotlin 里有哪些办法能达到类似的链式效果。

为什么 Kotlin 不支持赋值表达式
Java 中赋值表达式的返回值就是被赋的值本身,所以 int x = (y = 5) + 1 这种写法是合法的。这个特性偶尔能减少代码量,但它带来的问题比收益更大。最经典的坑就是把比较运算写成了赋值,例如:
int a = 1, b = 2;
// 本意是比较,结果变成赋值,条件永远为 true
if (a = b) {
// 老式写法里这是合法的(boolean 场景)
}
Kotlin 的设计哲学是让常见错误在编译期就被拦截。既然赋值不返回值,if (a = b) 在 Kotlin 里根本编译不过,必须老老实实写 ==。同样被砍掉的还有 ++ 作为表达式的副作用技巧。这样做牺牲了一点紧凑性,换来的是代码意图更清晰、更不容易埋雷。
另外,Kotlin 中属性赋值实际上会调用 setValue 操作符或者 setter 函数,这个操作可能触发任意逻辑,把它包装成一个有确定返回值的表达式语义上并不严谨。所以从语言设计层面,赋值就干脆只作为语句存在。
最直接的替代方案:拆开赋值
如果你只是想把同一个值赋给多个变量,最简单也最推荐的方式就是分行写:
var a = 0 var b = 0 var c = 0 // 直接分别赋值 a = 10 b = 10 c = 10
看起来啰嗦一点,但可读性反而更好。review 代码的人一眼就能看明白每一行在干什么,不会出现 Java 里那种一行链式赋值需要从右往左脑内解析的过程。对于初始化场景,还可以写成更简洁的形式:
val value = 10
val (a, b, c) = Triple(value, value, value)
println("$a $b $c") // 10 10 10
解构声明在很多场景下比链式赋值更直观,特别是变量本身就是成组出现的时候。如果变量类型一致,也可以用数组或列表配合解构一起用,不过要注意解构的变量个数必须和结构中的元素个数对得上,否则会编译报错。
用 apply 和 also 实现链式对象操作
Java 链式赋值最常见的实际用途之一,是创建对象后立刻赋值并继续使用,比如 list = new ArrayList<>(); list.add(1); 之类。在 Kotlin 里,标准库提供的 apply 和 also 天生就是为了这类链式调用设计的,而且比链式赋值更强大:
data class User(var name: String = "", var age: Int = 0)
val user = User().apply {
name = "张三"
age = 25
}
// also 返回对象本身,适合插入一些附加操作
val configured = User().also {
println("正在创建用户: $it")
}.apply {
name = "李四"
}
apply 在 lambda 内部以 this 引用对象,适合批量设置属性;also 以 it 引用对象并原样返回,适合在链式流程中插入日志、校验等旁路逻辑。两者返回的都是对象本身,因此可以无限串联,效果上比 Java 的赋值链更灵活。
需要注意的一点是,apply 里对属性的赋值仍然是语句,只是这些语句被包在一个表达式(lambda 调用)里,最终整个表达式的值是对象本身。这也体现了 Kotlin 的思路:链式能力由函数返回值提供,而不是由赋值提供。
自定义函数模拟链式赋值效果
如果确实需要把值传播下去的效果,可以自己写一个泛型扩展函数,把赋值动作封装成有返回值的表达式:
// 让赋值动作返回被赋的值
infix fun <T> T.assignTo(target: kotlin.reflect.KMutableProperty0<T>): T {
target.set(this)
return this
}
var a = 0
var b = 0
var c = 0
fun main() {
10 assignTo ::a assignTo ::b assignTo ::c
println("$a $b $c") // 10 10 10
}
这段代码通过属性引用 ::a 拿到可变属性的 setter,把 10 依次写入 a、b、c,同时每次都返回原值,于是可以像中缀表达式一样串起来。写法上确实接近 Java 的链式赋值,但我不太建议在正式项目中这么干。
原因有两个:一是可读性依赖团队对这个中缀函数的熟悉程度,新人看到 10 assignTo ::a 大概率要愣一下;二是它绕过了语言本身的设计意图,等于把 Kotlin 故意堵上的口子又手动挖开。这类技巧更适合作为理解语言机制的学习案例,日常开发中,老老实实分开赋值或者用 apply 才是正路。
总结
Kotlin 取消赋值表达式是刻意的设计取舍,用一点点书写上的便利换取更高的安全性。遇到想写链式赋值的场景,先想想真实需求是什么:如果是给多个变量赋同一个值,分开写或者用解构声明;如果是对象的配置和后续使用,apply 和 also 是更地道的答案;真有特殊需要,再考虑用属性引用封装自定义函数。理解了赋值在 Kotlin 中只是语句这一点,很多看似奇怪的编译报错也就顺理成章了。
Kotlin赋值链式语法Java链式赋值apply函数修改时间:2026-09-06 01:58:36