跳过正文

变量:variable

··1275 字
Rust
rust-lang - 这篇文章属于一个选集。
§ 2: 本文

使用 let 关键字声明变量, 默认不可变( immutable ),使用 mut 声明可变变量。

fn main() {
    let _immutable_binding = 1;
    let mut mutable_binding = 1;

    println!("Before mutation: {}", mutable_binding);
    mutable_binding += 1;
    println!("After mutation: {}", mutable_binding);

    // Error! Cannot assign a new value to an immutable variable
    _immutable_binding += 1;
}

Rust 是强类型静态语言,各变量都需要明确的类型。但一般不需要指定类型,编译器可以根据当前赋值或后续操作、赋值等情况,对变量类型进行自动推导:

// 编译器根据 expresion 结果或者后续对 var 的使用方式进行推导。
let var = expression;

fn main() {
    // 数值类型可以使用类型后缀
    let elem = 5u8;

    // Vec 是泛型类型,元素类型由 Rust 推导,等效于:
    // let mut vec: Vec<_> = Vec::new();
    let mut vec = Vec::new();
    vec.push(elem);
    println!("{:?}", vec);
}

变量必须先被声明并且初始化后才能使用,声明和初始化可以分开进行:

fn main() {
    let another_binding;
    // 变量被声明后未初始化,使用时报错。
    // println!("another binding: {}", another_binding);

    // 变量被初始化后可以使用。
    another_binding = 1;
    println!("another binding: {}", another_binding);

    // 先声明变量,但未初始化。
    let a_binding;
    {
        let x = 2; // 声明并初始化变量
        a_binding = x * x; // 变量被首次初始化后,后续才能使用。
    }
    println!("a binding: {}", a_binding);

    // 使用复杂的条件判断来初始化变量。
    let name;
    if user.has_nickname() {
        name = user.nickname();
    } else {
        name = generate_unique_name();
        user.register(&name);
    }
}

Rust block 可以返回值, 可用于初始化复杂的变量值:

let msg = {
    let dandelion_control = puffball.open();
    dandelion_control.release_all_seeds(launch_codes);

    // 表达式结尾没有分号,结果作为 block 的返回值。
    dandelion_control.get_status()
};

// match/if/loop 等语句均有返回值,各分支返回值类型必须一致。
let display_name = match post.author() {
    Some(author) => author.name(),
    None => {
        let network_info = post.get_network_metadata()?;
        let ip = network_info.client_address();
        ip.to_string()
    }
};

// 如果 if 表达式结果没有用于赋值, 则 block 不能有返回值:
let suggested_pet = if with_wings { Pet::Buzzard } else { Pet::Hyena }; // OK
if preferences.changed() {
    page.compute_size()  // oops, missing semicolon
}
// error[E0308]: mismatched types
//   22 |         page.compute_size()  // oops, missing semicolon
//       |         ^^^^^^^^^^^^^^^^^^^- help: try adding a semicolon:
//   `;`
// ||
// | expected (), found tuple |
// = note: expected unit type `()`
//                 found tuple `(u32, u32)`

Rust 变量默认 都需要被使用 ,否则编译器警告,解决办法:

  1. 在变量名前加 _ 来表明该变量可能不被使用;
  2. 添加 #![allow(unused)]#[allow(unused)] 属性宏;
fn main() {
    let an_integer = 1u32;
    let a_boolean = true;
    let unit = ();

    println!("A boolean: {:?}", a_boolean);
    println!("Meet the unit value: {:?}", unit);

    // 忽略警告
    let _unused_variable = 3u32;
}

变量名是 block scope

  • 变量可以被 shadow(同 block 或子 block shadow 同级或父级定义的同名变量),但 shadow 并不会 drop 前面变量的值;
  • shadow 可以为同名变量指定不同的可变性和变量值类型;
fn main() {
    // 未使用变量 shadow 时,需要定义临时变量
    for line_result in file.lines() {
        let line = line_result?;
        // ...
    }

    // 使用同名变量 shadow,减少一个变量定义
    for line in file.lines() {
        let line = line?;
        // ...
    }

    let x = 5;
    let x = x + 1; // shadow 上一个变量 x
    {
        let x = x * 2; // shadow 上一级变量 x
        println!("The value of x in the inner scope is: {}", x);
    }
    // shadow 不会 drop 对象, x 继续使用
    println!("The value of x is: {}", x);

    let shadowed_binding = 1;
    {
        let shadowed_binding = "abc"; // shadow 的变量类型可以不同
    }
    println!("outside inner block: {}", shadowed_binding);

    let shadowed_binding = 2;
    println!("shadowed in outer block: {}", shadowed_binding);

    let mut _mutable_integer = 7i32;
    {
        // shadow 时去掉了 mut,变量不可变
        let _mutable_integer = _mutable_integer;
        _mutable_integer = 50; // 报错!
    }
    _mutable_integer = 3; // shadow 结束,变量恢复为前面外层定义的可变变量
}

Rust 默认不对变量做自动类型转换,但是在变量赋值, 函数传参等场景, Rust 会隐式的做类型转换,称为 type coercion

在表达式中使用 as 运算符进行显式类型转换:

#![allow(overflowing_literals)]
fn main() {
    let decimal = 65.4321_f32;
    // 错误:除了 type coercion 外,不同类型变量值之间不能赋值
    let integer: u8 = decimal;

    // Explicit conversion
    let integer = decimal as u8;
    // integer 作为 unicode point,可以被转换为 char
    let character = integer as char;
    // 错误,浮点数不能被转换为 char
    let character = decimal as char;

    // OK, u16 可以存下 1000
    println!("1000 as a u16 is: {}", 1000 as u16);
   // 向低类型转换时,超出的高字段被丢弃。
    println!("1000 as a u8 is : {}", 1000 as u8);
    // -1 + 256 = 255
    // -1 的符号位对于 u8 来说是 +256;
    println!("  -1 as a u8 is : {}", (-1i8) as u8);
    println!("1000 mod 256 is : {}", 1000 % 256);
    println!(" 128 as a i8 is : {}", 128 as i8); // -128
    // 300.0 as u8 is 255
    println!(" 300.0 as u8 is : {}", 300.0_f32 as u8);
    // -100.0 as u8 is 0
    println!("-100.0 as u8 is : {}", -100.0_f32 as u8);
    // nan as u8 is 0
    println!("   nan as u8 is : {}", f32::NAN as u8);
}
rust-lang - 这篇文章属于一个选集。
§ 2: 本文

相关文章

不安全:unsafe
··824 字
Rust
Rust
借用:refer/borrow
··3127 字
Rust
Rust 引用类型和借用
函数、方法和闭包:function/method/closure
··7032 字
Rust
Rust 函数、方法和闭包
包和模块:package/crate/module
··2066 字
Rust
Rust 项目的包和模块组织结构