第3章:Kotlin基础语法(一):变量声明(val vs var)、类型推断、基本数据类型、字符串模板
好,咱们正式开始写Kotlin代码了。
说实话,从Java转到Kotlin,第一个让我觉得「哇,真香」的地方,就是变量声明。Java里写个变量,你得先想好类型,再写变量名,再赋值。Kotlin呢?一句话就能搞定,而且更安全。
这一章,咱们就把变量声明、类型推断、基本数据类型和字符串模板这几个最基础的东西讲透。别小看这些基础,我见过不少老Android开发,写Kotlin半年了,还在用Java的思维写val和var,结果踩了不少坑。
3.1 val vs var:不可变优先
先看个对比,你感受一下:
// Java
final String name = "张三";
String age = 18;
// Kotlin
val name = "张三"
var age = 18
val 对应 Java 的 final,表示只读变量,赋值后不能改。var 就是普通可变变量。
我个人习惯是:能用val就不用var。为什么?
- val 让代码更安全,别人不会意外修改你的变量
- val 更容易推理,看到 val 就知道这个值不会变
- val 在多线程环境下更友好
但要注意,val 不等于 Java 的 final 那么简单。val 指向的对象内部状态是可以变的:
val list = mutableListOf("A", "B")
list.add("C") // 可以!list指向没变,但内容变了
// list = mutableListOf("D") // 编译错误!不能重新赋值
嗯,这里要注意:val 保证的是引用不可变,不是对象不可变。如果你想要完全不可变,得用不可变集合或者数据类配合 copy()。
3.2 类型推断:少写一半代码
Kotlin 有强大的类型推断能力。说白了,编译器能根据右边的值,自动推断出变量的类型。
val name = "张三" // 推断为 String
val age = 18 // 推断为 Int
val height = 1.75 // 推断为 Double
val isStudent = true // 推断为 Boolean
这比Java省事多了。Java里你得写:
String name = "张三";
int age = 18;
Kotlin 把左边的类型声明给省了。但注意,类型推断不是万能的。有些情况你还是得显式声明类型:
- 函数返回值类型模糊时
- 你想让变量是父类型而不是子类型时
- 递归函数
避坑指南:我曾经在项目里遇到过一个bug,就是因为类型推断推错了。当时我写了个 val result = someFunction(),结果someFunction返回的是 Any?,我以为是String,直接调用了length,编译没过。后来我养成了习惯:对于复杂表达式,显式声明类型更安全。
你也可以手动指定类型,虽然不常用:
val name: String = "张三"
val age: Int = 18
我个人建议:简单变量用推断,复杂表达式或者公共API的返回值,显式声明类型更好。
3.3 基本数据类型:一切皆对象
Java 里基本类型和引用类型是分开的,int、boolean 这些不是对象。Kotlin 不一样,一切皆对象。
Kotlin 的基本数据类型包括:
| 类型 | 说明 | Java对应 |
|---|---|---|
| Int | 整型,32位 | int / Integer |
| Long | 长整型,64位 | long / Long |
| Float | 单精度浮点,32位 | float / Float |
| Double | 双精度浮点,64位 | double / Double |
| Boolean | 布尔值 | boolean / Boolean |
| Char | 单个字符 | char / Character |
| String | 字符串 | String |
在Kotlin里,这些类型都是类,你可以调用它们的方法:
val num = 42
println(num.toString()) // "42"
println(num.toLong()) // 42L
println(num.rangeTo(50)) // 42..50
你想想看,Java里你能对int直接调用方法吗?不行,得先装箱成Integer。Kotlin 帮你省掉了这个麻烦。
Int?),那就必须装箱了。所以,能用非空类型就用非空类型,性能更好。
数字字面量还有一些小技巧:
val oneMillion = 1_000_000 // 下划线分隔,方便阅读
val hexBytes = 0xFF_EC_DE_5E
val bytes = 0b11010010_01101001_10010100_10010010 // 二进制字面量
嗯,这个下划线分隔,我在写金额、ID的时候特别喜欢用,一眼就能看出位数。
3.4 字符串模板:告别拼接噩梦
Java里拼接字符串有多痛苦?
String name = "张三";
int age = 18;
String message = "我叫" + name + ",今年" + age + "岁。";
写多了手都酸,而且容易漏掉加号或者引号。Kotlin 的字符串模板直接解决了这个问题:
val name = "张三"
val age = 18
val message = "我叫$name,今年${age}岁。"
用 $ 加变量名,就能直接把变量嵌入到字符串里。如果变量后面紧跟其他字符,或者要调用方法,就用 ${} 包起来。
更复杂的表达式也可以:
val price = 19.99
val count = 3
val total = "总价:${price * count} 元" // 输出:总价:59.97 元
甚至可以在模板里调用方法:
val name = "zhang san"
val upperName = "大写:${name.uppercase()}" // 输出:大写:ZHANG SAN
Log.d(TAG, "用户$userId 在${formatDate(time)} 执行了操作"),比用加号拼接舒服多了。
另外,Kotlin 还支持原始字符串,用三个引号 """ 包裹,可以保留换行和缩进:
val json = """
{
"name": "张三",
"age": 18
}
""".trimIndent() // 去掉前导空格
这个在写多行文本、JSON、SQL 的时候特别有用。我曾经在项目里用原始字符串写了一段复杂的SQL查询,同事看了都说清晰。
小结
这一章的内容其实不多,但都是日常写Kotlin的基础。总结一下:
- val vs var:优先用val,只有需要改变时才用var
- 类型推断:能省则省,但复杂场景显式声明更安全
- 基本数据类型:一切皆对象,但注意可空类型会装箱
- 字符串模板:用$和${},告别拼接噩梦
下一章,咱们会继续深入Kotlin的函数和条件控制。到时候你会发现,Kotlin 在流程控制上也有很多让人眼前一亮的设计。准备好了吗?