3、基础语法:变量声明(var/val)、基本数据类型(Int、Double、Boolean、Char、String)、类型推断、字符串模板

Kotlin 作为一门现代静态类型编程语言,其变量声明与类型系统设计得既严谨又灵活。与 Java 相比,Kotlin 在语法层面做了大量简化,例如通过 var 与 val 区分可变与不可变引用,通过类型推断减少冗余代码,同时引入了强大的字符串模板机制。理解这些基础语法是构建复杂业务逻辑的基石。本章将深入剖析变量声明的本质、基本数据类型的底层表示、类型推断的规则,以及字符串模板的高效用法,帮助你在编码实践中建立正确的内存与类型意识。

Kotlin 变量与类型系统核心概念关系图 变量声明与类型体系 var / val var: 可变引用 val: 只读引用(不可变) 基本数据类型 Int / Double / Boolean Char / String 类型推断 编译器自动推导类型 减少冗余代码 字符串模板 \${变量} 或 \$变量 支持表达式求值 核心:类型安全 + 不可变性优先 + 简洁表达

3.1 核心原理:var 与 val 的本质区别

在 Kotlin 中,声明变量使用两个关键字:var(可变变量)和 val(不可变变量)。这一设计直接借鉴了函数式编程思想,旨在从语法层面强制开发者思考数据的可变性。一个 val 声明的变量,其引用(即存储地址)在初始化后不可更改,但这并不意味着其指向的对象内部状态不可变。例如,val list = mutableListOf(1,2,3) 中,list 的引用不能重新赋值,但列表内容可以增删。而 var 则允许重新赋值,但需注意类型必须严格匹配。

核心原则:优先使用 val,仅在确有必要时才使用 var。这能显著减少因变量意外被修改而引发的并发或逻辑错误。

3.2 基本数据类型与类型推断

Kotlin 的基本数据类型包括 Int(32位整数)、Double(64位浮点数)、Boolean(布尔值)、Char(16位字符)、String(字符串)。与 Java 不同,Kotlin 中这些类型都是对象,但编译器会进行优化,在大多数情况下仍以基本类型运行,兼顾性能与安全。类型推断是 Kotlin 的一大亮点:编译器能根据赋值表达式的值自动推导出变量类型,从而省略显式类型声明。

// 显式声明类型
val count: Int = 10
// 类型推断(推荐)
val count = 10          // 自动推断为 Int
val price = 19.99       // 自动推断为 Double
val isActive = true     // 自动推断为 Boolean
val grade = 'A'         // 自动推断为 Char
val name = "Kotlin"     // 自动推断为 String

需要注意的是,类型推断发生在编译期,一旦推断完成,变量类型即被固定。例如 var x = 5 后,x 的类型为 Int,不能再赋值为 "hello"。此外,Kotlin 中不存在自动提升类型转换,如 Int 不能直接赋给 Long,必须显式调用 toLong() 方法。

数据类型占用位数取值范围/示例典型应用场景
Int32位-2^31 至 2^31-1计数器、索引、ID
Double64位约 ±1.7E+308科学计算、金额(需注意精度)
Boolean1位(逻辑上)true / false条件判断、标志位
Char16位单个字符,如 'a'、'中'字符处理、遍历字符串
String动态任意字符序列文本展示、拼接、格式化

3.3 字符串模板:优雅的文本拼接方案

字符串模板是 Kotlin 提供的一项极具生产力的特性,它允许在字符串字面量中直接引用变量或表达式,以 $ 符号开头。对于简单变量,使用 $variableName;对于复杂表达式,使用 ${expression}。这一特性彻底告别了 Java 中繁琐的 "Hello, " + name + "!" 拼接方式。

val user = "Alice"
val age = 28
val message = "User: $user, Age: $age"  // 输出: User: Alice, Age: 28
val price = 9.99
val desc = "Price is ${price * 2}"      // 表达式求值,输出: Price is 19.98
val raw = "The sum is ${1 + 2}"         // 输出: The sum is 3

字符串模板不仅支持变量和算术表达式,还支持调用函数、访问对象属性等。例如 "Length is ${name.length}"。在需要输出美元符号本身时,需使用转义 \$。此外,Kotlin 还支持原始字符串(三引号 """),其中可以包含换行和特殊字符,且模板语法依然生效。

实战建议:在日志输出、错误提示、SQL 拼接等场景中,优先使用字符串模板而非传统拼接,可显著提升代码可读性与维护性。

3.4 案例拆解:用户信息格式化与校验

假设我们需要开发一个用户注册模块,要求将用户输入的信息格式化为标准字符串,并进行基础校验。以下代码展示了变量声明、类型推断与字符串模板的综合应用。

fun formatUserInfo(name: String, age: Int, email: String?): String {
    // 使用 val 声明不可变变量,保证数据不被意外修改
    val trimmedName = name.trim()
    val normalizedEmail = email?.trim()?.lowercase() ?: "未提供"
    
    // 使用字符串模板构建输出
    return """
        |用户信息:
        |姓名:$trimmedName
        |年龄:${if (age in 18..60) "成年($age 岁)" else "未成年或高龄($age 岁)"}
        |邮箱:$normalizedEmail
    """.trimMargin()
}

fun main() {
    val info = formatUserInfo("  Alice  ", 25, " Alice@Example.COM ")
    println(info)
}

在上述案例中,我们通过 val 确保中间变量不可变,利用类型推断简化声明,并通过字符串模板嵌入条件表达式 ${if (age in 18..60) ...} 实现动态文本。输出结果如下:

用户信息:
姓名:Alice
年龄:成年(25 岁)
邮箱:alice@example.com

该案例展示了如何将基础语法应用于实际业务逻辑,同时体现了 String? 可空类型的安全调用(?.let)与 Elvis 操作符(?:)的配合,这是 Kotlin 类型系统的精髓之一。

3.5 常见误区与总结复盘

在学习变量声明时,初学者常陷入以下误区:

  • 混淆 val 与不可变对象:val 只保证引用不变,不保证对象内部状态不变。例如 val list = mutableListOf(1) 后,list.add(2) 是合法的。
  • 过度依赖类型推断:虽然类型推断方便,但在某些场景下显式声明类型更清晰,例如函数返回值或复杂泛型表达式。
  • 忽略类型转换的显式性:Kotlin 不允许隐式拓宽转换,如 val x: Long = 10 会编译错误,必须写 val x: Long = 10L 或 10.toLong()。
  • 字符串模板中的转义问题:在模板中输出 $ 符号时,必须使用 \$,否则会被解析为变量引用。

风险提示:在团队协作中,滥用 var 会导致代码难以追踪状态变化,尤其在多线程环境下容易引发数据竞争。建议在代码评审中强制要求:所有变量默认声明为 val,除非有明确的性能或逻辑需求。

总结而言,Kotlin 的变量声明与类型系统设计体现了现代语言对安全性与简洁性的追求。通过合理使用 var/val、理解基本数据类型的特性、善用类型推断与字符串模板,开发者可以写出更健壮、更易读的代码。建议在后续学习中,始终带着“能否用 val?”和“能否用模板简化?”这两个问题去审视每一段代码,逐步培养良好的编码习惯。