rust学习 -- 第一章 变量

96 阅读4分钟

第一章

变量声明

let variable: i32 = 100;

变量名: 变量类型 = 变量值

注意变量的声明和初始化可以是分开的, 只要在使用之前初始化了即可

fn test(confition: bool) {
    let x: i32; // 声明x, 不必使用mut修饰
    if condition {
        x = 1;  // 初始化x, 不需要x是mut的, 因为这是初始化,不是修改.
        println!("{}", x);
    }
    // 如果条件不满足,x 没有被初始化  但是没关系,只要这里不使用 x 就没事
}

常量声明

const MAX_POINTS: u32 = 100_000;
const POLICY_BASELINE: &'static str = "some strings";

常量在绑定一个值后也是不可变的.

  • 不能使用mut,常量永远不可变
  • 声明常量使用const关键字,类型必须被标注
  • 常量可以在任何作用域内进行声明,包括全局作用域
  • 常量只可以绑定到常量表达式,无法绑定到函数的调用结果或者只能在运行时才能计算出大小的类型

静态变量

rust中可以用static关键字声明静态变量

static GLOBAL: i32 = 0;

与let语句一样,static语句同样也是一个模式匹配.与let语句不同的是,用static声明的变量的生命周期是整个程序,从启动到退出.static 变量的生命周期永远是'static,它占用的内存空间也不会在执行过程中回收.这也是Rust中唯一的声明全局变量的方法.

全局变量使用有很多限制

  • 全局变量必须在声明的时候马上初始化;
  • 全局变量的初始化必须是编译期可确定的常量,不能包括执行期才能确定的表达式、语句和函数调用;
  • 带有mut修饰的全局变量,在使用的时候必须使用unsafe关键字
fn main() {
    // 局部变量声明, 可以留在后面初始化, 只要保证使用前已经初始化即可
    let x;
    let y = 1_i32;
    x = 2_i32;
    println!("{} {}", x, y);
    // 全局变量必须声明的时候初始化, 因为全局变量可以写到函数外面, 被任意一个函数使用
    static G1: i32 = 3;
    println!("{}", G1);
​
    // 可变全局变量 无论读写都必须用 unsafe修饰
    static mut G2: i32 = 4;
    unsafe {
        G2 = 5;
        println!("{}", G2);
    }
    //全局变量的内存不是分配在当前函数栈上,函数退出的时候,并不会销毁全局变量占用的内存空间,程序退出才会
}

静态变量和常量的区别:

静态变量强调的是存在周期长, 在整个程序的声明周期. 常量强调的是不可变.

便捷用法

省略类型

变量类型可以省略, 如果可以从上下文中推导出变量类型.

fn main() {
    // 没有明确标出变量的类型, 但是通过字面量的后缀,编译器知道elem的类型为u8
    let elem = 5u8;
​
    // 创建一个动态数组, 数组内部包含的是什么元素类型可以不写
    let mut vec = Vec::new();
    vec.push(elem);
    // 后面调用了push函数,通过elem变量的类型, 编译器可以推导出vec的实际类型是 Vec<u8>
​
    println!("{:?}", vec);
​
}

模式解构

let 语句在此处引入了一个模式解构, 不能把let mut视为一个组合,而应该将mut x视为一个组合. mut x是一个“模式”,我们还可以用这种方式同时声明多个变量:

let (mut a, mut b) = (1, 2);
let Point { x: ref a, y: ref b} = p;

在Rust中,一般把声明的局部变量并初始化的语句称为“变量绑定”,强调的是“绑定”的含义,与C/C++中的“赋值初始化”语句有所区别.

shadowing 变量遮蔽

可以使用相同的名字声明新的变量,新的变量就会shadow(隐藏)之前声明的同名变量,在后续的代码中这个变量名就是新变量.

fn main(){
    let spaces = "    ";
    let spaces = spaces.len();  // 可以改变变量的类型
}

类型别名

可以用type关键字给同一个类型起个别名(type alias)

type Age = u32;
​
fn grow(age: Age, year: u32) -> Age {
    age + year
}
​
fn main() {
    let x: Age = 20;
    println!("20 years later: {}", grow(x, 20));
}

类型别名还可以用在泛型场景

type Double<T> = (T, Vec<T>); // 小括号包围的是一个 tuple, 参考后面的复合类型