MST

星途 面试题库

面试题:Rust中const和static在内存布局上的区别

请详细阐述在Rust语言里,使用const和static声明的变量在内存布局方面有何不同?并举例说明这种不同对程序运行可能产生的影响。
34.6万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

内存布局不同

  1. const声明的常量
    • 存储位置const声明的常量在编译时就会被求值并内联到使用它的地方。它不会在运行时占用独立的内存空间。例如:
    const FIVE: i32 = 5;
    fn main() {
        let x = FIVE + 3;
    }
    
    在编译后的代码中,FIVE不会有单独的内存存储,let x = FIVE + 3;这行代码在编译时会直接处理为let x = 5 + 3;
    • 类型要求const常量的类型必须是Copy类型,并且其值必须在编译时就能确定。这是因为它要内联到使用的地方,不能依赖运行时的计算。
  2. static声明的静态变量
    • 存储位置static声明的静态变量有自己独立的内存地址,在程序的整个生命周期内存在于静态内存区域。例如:
    static mut COUNTER: i32 = 0;
    fn main() {
        unsafe {
            COUNTER += 1;
            println!("COUNTER: {}", COUNTER);
        }
    }
    
    COUNTER在静态内存中有自己的存储位置,可以在运行时通过其地址来访问和修改(这里因为COUNTERmut可变的,并且访问可变静态变量需要unsafe块)。
    • 类型限制相对宽松static变量可以是任何类型,包括非Copy类型。不过如果是可变的static变量(mut修饰),访问时需要unsafe代码块,因为多个线程可能同时访问它,容易引发数据竞争。

对程序运行影响举例

  1. const常量
    • 优点:由于内联,不会有额外的内存访问开销,提高了程序的运行效率。特别是在多次使用同一个常量值的情况下,不会因为重复存储常量值而浪费内存。例如在一个循环中多次使用const常量:
    const ONE: i32 = 1;
    fn main() {
        for _ in 0..10 {
            let result = ONE + 2;
            println!("{}", result);
        }
    }
    
    编译后,循环中的ONE直接被替换为1,没有额外的内存访问操作。
    • 缺点:如果常量值需要修改,那么需要修改源代码并重新编译整个程序,因为常量值是编译时确定的。
  2. static变量
    • 优点:可以在运行时修改其值,并且可以在程序的不同部分共享这个变量。例如在一个多函数的程序中共享一个静态计数器:
    static mut COUNTER: i32 = 0;
    fn increment_counter() {
        unsafe {
            COUNTER += 1;
        }
    }
    fn print_counter() {
        unsafe {
            println!("COUNTER: {}", COUNTER);
        }
    }
    fn main() {
        increment_counter();
        increment_counter();
        print_counter();
    }
    
    这里不同的函数可以通过静态变量COUNTER共享数据。
    • 缺点:由于存在于静态内存且生命周期长,可能会导致内存占用增加。而且可变静态变量的访问需要unsafe代码块,使用不当容易引发内存安全问题,如数据竞争(在多线程环境下)。