Rust 从函数式语言中借鉴了 let 关键字建立变量。 Let 建立的变量通常称为绑定(Binding),它代表了标识符(Identifier)和值(value)之间创建的一种关联关系。数组
Rust 中的表达式通常能够分为位置表达式(Place Expression)和值表达式(Value Expression)。安全
位置表达式即表示内存位置的表达式。分为markdown
经过位置表达式能够对某个数据单元的内存进行读写。主要是进行写操做,也就是位置表达式能够被赋值的缘由。函数
除了位置表达式之外的表达式就是值表达式。 值表达式通常值引用了某个存储单元地址中的数据。至关于数据值,只能进行读操做。spa
从语义角度讲, 位置表达式表明了数据持久性数据,值表达式表明了临时数据。位置表达式通常有持久状态,值表达式通常为字面量或为表达式求值过郑重建立的临时值。指针
表达式的求值过程在不一样的上下文中会有不一样的结果。求值上下文也分为位置上下文(Place Context)和值上下文(Value Context)code
a = b + c
其中 a 就是位置上下文除此之外都是值上下文。值表达式不能出如今位置上下文中。示例以下:orm
pub fn temp() -> i32 {
return 1;
}
fn main () {
let x = &temp(); // temp 函数调用是一个无效的位置表达式
temp() = *x; // error 报错
}
复制代码
函数 temp 的调用放到了赋值语句左边的位置上下文中,此时编译器报错,由于 temp 函数调用的是一个无效的位置表达式,它是值表达式。索引
使用 let 关键字声明的位置表达式默认不可变,为不可变绑定,简单来说,就 是 let 声明的变量不可变,相似于 JavaScript 中的 const 关键字。ip
fn main () {
let a = 1; // a 不可变
// a = 2; immutable and error
let mut b = 2; // 增长可变声明
b = 3;
}
复制代码
经过 mut 关键字,能够声明可变的位置表达式,便可变绑定,可变绑定能够正常修改和赋值。
从语义上来说,let 默认声明的不可变绑定只能对相应的存储单元进行读取,而 let mut 声明的可变绑定则是能够对相应的存储单元进行写入的。
当位置表达式出如今值上下文中时,该表达式会把内存地址转移给另一个位置表达式,这实际上是全部权转移。
fn main () {
let place1 = "hello";
let place2 = "hello".to_string();
let other = place1;
println!("{:?}", other);
let other = place2;
println("{:?}", other) // error
}
复制代码
上面代码中使用 let 声明了两个绑定, place1 和 place2。而后将 place1 赋值给新的变量 other。 由于 place1 是一个位置表达式,出如今了赋值操做符的右侧,即一个值上下文内,因此 place1 会将内存地址转移给 other。同理 将 place2 复制给新声明的 other ,place2 的内存地址一样会转移给 other。
第二次声明 other 将 place2 地址赋值给 other 时,会出现报错,意为该处使用了已经移动的值,之因此会出现这种区别,实际上是和底层内存安全管理有关系。这两种行为虽然有差异,都是 Rust 为了安全刻意为之。
在语义上,每一个变量绑定实际上都拥有该存储单元的全部权,这种转移内存地址的行为就是全部权(OwnerShip) 的转移,在 Rust 中移动(Move)语义,那种不转移的状况其实是一种复制(Copy)语义。Rust 无 GC,因此彻底靠全部权来进行内存管理。
在开发中,通常不须要转移全部权。Rust 提供了引用操做符(&),能够直接获取表达式的存储单元地址,即内存为止。能够经过该内存位置对内存进行读取。
fn main () {
let a = [1,2,3];
let b = &a; // 获取内存地址,至关于指针
println!("{:p}", b);
let mut c = vec![1,2,3];
let d = &mut c;
d.push(4);
println!("{:?}", d);
}
复制代码
上面代码中,b 以 & 的方式获取 a 的内存地址,这种方式不会引发全部权转移,由于使用引用操做符已经将赋值表达式右侧变成了位置上下文,它知识共享内存位置,经过 println! 宏指定{:p} 格式,能够打印 b 的指针地址,也就是内存地址。
经过 let mut 声明动态常数数组c ,经过 &mut 可获取 c 的可变引用,赋值给 d, 对于 d 的 push 操做,插入新的元素 4。要获取可变引用,必须先声明可变绑定。
不管是&a 仍是 &mut c 都至关于对于 a 和 c 全部权的借用,由于 a 和 c 还依旧保留他们的全部权,因此引用也称之为借用。