Swift 变量与常量
"变量"是程序里存放数据的容器。Swift 用两个关键字 let 和 var 来声明,看似简单,但背后藏着 Swift 关于"安全"和"意图清晰"的重要设计哲学。本章讲透它。
1. let 与 var:一字之差,天壤之别
Swift 声明变量只用两个关键字:
- let:声明常量(constant),赋值后不能再改。
- var:声明变量(variable),可以反复修改。
// let:常量,声明后不可改(类似 const)
let pi = 3.14159
let languageName = "Swift"
// pi = 3.14 // 编译错误:let 不能重新赋值
// var:变量,可以修改
var counter = 0
counter = counter + 1
counter += 1
print(counter) // 2这看起来和 C/Java 的 const / let 没区别,但 Swift 的特别之处在于:默认应该用 let,只有需要修改时才用 var。这是社区约定,Xcode 也会给"应该用 let 的 var"黄色警告。理由是——不可变代码更容易理解、更容易并发安全。
2. 类型推断 vs 显式标注
Swift 是静态类型语言——每个变量都有确定的类型。但大多数时候你不用写类型,编译器会自动推断:
// 类型推断:不写类型,编译器自动判断
let age = 25 // 推断为 Int
let price = 9.99 // 推断为 Double(不是 Float!)
let name = "小明" // 推断为 String
let isOpen = true // 推断为 Bool
// 显式类型标注:在变量名后加冒号和类型
let score: Int = 88
let rate: Double = 0.5
let label: String = "VIP"
let isValid: Bool = false
// 推断不出来或想用更窄类型时,显式标注
let weight: Float = 65.5 // 否则会推断为 Double几个新手容易踩坑的点:
- 小数字面量默认是 Double而不是 Float,需要 Float 要显式标注。
- 整数默认是 Int(在 64 位平台是 Int64)。
- 布尔只有两个值:
true和false(全小写)。0/1 不能当 Bool 用,这点和 C/Python 不一样。 - 当类型推断不出来(比如空数组
[])或你想用更窄的类型时,再显式标注。
3. 多变量与元组
Swift 支持一次声明多个变量,以及通过元组把多个值组合:
// 一次声明多个同类型变量
var x = 0, y = 0, z = 0
x += 1; y += 2; z += 3
print(x, y, z) // 1 2 3
// 元组:把多个值打包成一个
let coordinate = (lat: 39.9, lng: 116.4)
print(coordinate.lat) // 39.9
// 解构赋值
let (success, message) = (true, "OK")
print(success, message) // true OK
// 只取一部分,用下划线忽略
let (code, _) = (404, "Not Found")
print(code) // 404元组是 Swift 的一个亮点——其他语言(如 Python)也有,但 Swift 的元组可以命名元素,用起来像一个小 struct。函数返回多个值时尤其方便。
4. 变量作用域
每个变量只在声明它的代码块内有效。出了这个块就访问不到了。内层同名变量会"遮蔽"(shadow)外层:
// 作用域:变量只在声明它的代码块里有效
let globalGreeting = "Hi"
func talk() {
let localMsg = "Hello" // 只在 talk 内有效
print(globalGreeting) // 外层的能访问
print(localMsg)
}
talk()
// print(localMsg) // 编译错误:出了作用域
// 内层同名变量会"遮蔽"外层
let level = "外层"
if true {
let level = "内层"
print(level) // 内层
}
print(level) // 外层这条规则和绝大多数语言一致。Swift 多了一条:常量声明后必须在使用前初始化(可先声明后赋值,但不能"未赋值就用")。
5. 类型别名 typealias
用 typealias 可以给现有类型起一个更易读的名字,不创建新类型,只是别名(类似 C 的 typedef):
// typealias:给现有类型起个更可读的名字
typealias ID = String
typealias Coordinate = (lat: Double, lng: Double)
let userId: ID = "U123456"
let beijing: Coordinate = (lat: 39.9, lng: 116.4)
print(userId, beijing.lat)
// 常用于闭包类型,避免一长串泛型
typealias Callback = (Result<Data, Error>) -> Void
// Swift 标准库里的 typealias 例子
// Int 在 64 位平台就是 Int64
// Swift.String = String 重复定义无意义,但能提升可读性实战中 typealias 经常用于:让闭包类型签名更短、领域概念命名(把 String 起名 UserId 让代码意图清晰)、平台兼容(Int 在 32/64 位平台大小不同,Swift 替你处理了)。
6. 为何默认 let?Swift 的设计哲学
大多数语言里 const 是"加戏",而 Swift 把"不可变"作为默认推荐。原因有三:
- 可读性:看到
let你就知道这个值不会变,跟踪代码时心智负担小。 - 线程安全:不可变值天生线程安全,无需加锁。
- 编译优化:编译器对常量能做更激进的优化,代码更快。
建议:每次想用 var 时,先问自己"它真的需要变吗?"——能 let 就 let。
7. 常见陷阱
- let 引用类型:
let arr = [1,2,3]不能换成新数组,但可以修改元素吗?答案是不能(Swift 的 Array 是值类型,let完全冻结)。class 才会出现"let 但内容可变"。 - 未使用警告:声明了不用,Xcode 会警告,可以前置下划线消除:
let _unused = 1。 - 类型不匹配:
let x = 5; x = "5"直接编译错误,Swift 不会做隐式类型转换。
小结
这一章你学会了声明变量(var)和常量(let),知道 Swift 默认推荐 let;了解了类型推断、显式标注、元组解构、作用域、typealias。下一篇我们看 Swift 的数据类型——Int、Double、Bool、String 这些基础类型都有什么讲究。
← 上一篇 Swift 基础语法
下一篇 Swift 数据类型 →