
回复
作为在鸿蒙开发中被变量坑过的老司机,曾因引用类型误用导致设备数据错乱,也被编译器保守策略折磨过。本文结合实战经验,解析仓颉语言变量体系的生存法则,帮你避开变量相关的坑。
不可变变量在并发中是救命符,可变变量是定时炸弹:
// 危险的可变变量(并发场景)
var counter = 0
let thread1 = async { counter += 1 }
let thread2 = async { counter += 1 }
awaitAll([thread1, thread2])
println(counter) // 可能输出1(竞态条件)
// 安全的不可变变量(函数式风格)
let initial = 0
let result = awaitAll([
async { initial + 1 },
async { initial + 1 }
]).reduce(0, +)
println(result) // 确保输出2
实战原则:
let
,避免竞态条件AtomicReference
包装值类型像独立生命体,引用类型如同卵双胞胎:
// 值类型struct(独立生存)
struct Point {
var x: Int
var y: Int
}
let p1 = Point(x: 1, y: 2)
let p2 = p1 // 生成独立副本
p2.x = 3
println(p1.x) // 输出1(不受影响)
graph TD
A[栈内存] --> B[p1(x:1,y:2)]
A --> C[p2(x:1,y:2)]
// 引用类型class(共享生存)
class Point {
var x: Int
init(x: Int) { this.x = x }
}
let p1 = Point(x: 1)
let p2 = p1 // 共享同一对象
p2.x = 3
println(p1.x) // 输出3(被影响)
graph TD
A[栈内存] --> B[p1(指向堆对象)]
A --> C[p2(指向同一堆对象)]
D[堆内存] --> E[对象(x:1,后变为3)]
场景 | 选择类型 | 生存优势 |
---|---|---|
小数据独立操作 | struct | 复制高效,无共享风险 |
大数据共享操作 | class | 内存效率高,共享方便 |
编译器像过度保护的家长,必须确保变量"活下来":
// 编译器报错案例
let a: String
try {
a = "success"
} catch {
// 编译器认为a可能未初始化
// Error: Variable 'a' used before being initialized
}
生存方案:
let a: String = ""
let a: String? = nil
闭包捕获变量如同"寄生",需注意生命周期:
func createTimer() -> () -> Void {
var count = 0
return {
count += 1
println(count)
}
}
let timer = createTimer()
timer() // 输出1
timer() // 输出2(count被闭包捕获并保持状态)
struct BankAccount {
let id: String
var balance: Double
func withdraw(amount: Double) -> BankAccount {
// 返回新账户副本
return BankAccount(id: id, balance: balance - amount)
}
}
let account = BankAccount(id: "123", balance: 1000)
let newAccount = account.withdraw(amount: 200)
class BankAccount {
let id: String
var balance: Double
init(id: String, balance: Double) {
self.id = id
self.balance = balance
}
func withdraw(amount: Double) {
balance -= amount // 直接修改状态
}
}
let account = BankAccount(id: "123", balance: 1000)
account.withdraw(amount: 200)
let
,确需变更时再用var
struct
,大数据用class