Rust位置表达式和值表达式
Rust 里把表达式分为两类:
位置表达式 (place expression) —— 表示一个内存位置,可以作为赋值语句的左值。
值表达式 (value expression) —— 表示一个具体的值,只能作为右值。
1. 本地变量 (Local Variables)
本地变量本身就是位置表达式,可以存储和修改值。
fn main() {let mut x = 10; // x 是位置表达式x = 20; // 可以赋值,因为 x 是一个内存位置println!("{}", x);
}
2. 静态变量 (Static Variables)
静态变量有固定的内存位置,所以也是位置表达式。
static mut COUNTER: i32 = 0;fn main() {unsafe {COUNTER = 100; // 静态变量是位置表达式println!("{}", COUNTER);}
}
3. 解引用 (*expr)
对指针解引用后得到的是一个位置(指向的内存)。
fn main() {let mut x = 10;let y = &mut x;*y = 20; // *y 是位置表达式,表示 x 的位置println!("{}", x);
}
4. 数组索引 (expr[expr])
数组或切片的索引表达式是位置表达式。
fn main() {let mut arr = [1, 2, 3];arr[0] = 10; // arr[0] 是位置表达式println!("{:?}", arr);
}
5. 字段引用 (expr.field)
结构体的字段是位置表达式。
struct Point { x: i32, y: i32 }fn main() {let mut p = Point { x: 0, y: 0 };p.x = 10; // ✅ p.x 是位置表达式println!("({}, {})", p.x, p.y);
}
6. 位置表达式组合
比如 arr[0].field
、(*ptr).field
、struct.field[index]
之类的组合,依然是位置表达式。
struct Item { val: i32 }fn main() {let mut arr = [Item { val: 1 }, Item { val: 2 }];arr[1].val = 99; // ✅ arr[1].val 是位置表达式println!("{}", arr[1].val);
}
注意事项:
值表达式不能出现在位置上下文中
pub fn temp() -> i32 {return 1;}fn main() {let x = &temp();temp() = *x; //错误
}
其中&temp()表示获取temp()返回的临时变量的地址
当位置表达式出现在值上下文中时,该位置表达式将会把内存地址转移给另外一个位置
表达式,这其实是所有权的转移,如
fn main() {let a = "hello"; // a 的类型是 &str,字符串字面量,存储在静态区,不涉及所有权转移let b = "hello".to_string(); // b 的类型是 String,堆上分配内存,拥有所有权let ohter = a; // &str 可以 Copy,所以 a 依然可用println!("{:?}", ohter);let ohter = b; // String 没有实现 Copy,赋值时发生 move,b 的所有权转移给 ohterprintln!("{:?}", ohter);// println!("{}",a); // 正确 a 还能用,因为 a 没有被 move,只是复制了个指针// println!("{}",b); // 错误,因为 b 的所有权已经被转移走,b 无效
}