美文网首页Rust
关于Rust中常见的生命期的“例子”(一)

关于Rust中常见的生命期的“例子”(一)

作者: 神奇的考拉 | 来源:发表于2022-03-30 16:15 被阅读0次

    一、说明

    类型 含义 样例
    T 1、所有可能的类型集合或其中一个具体类型 T,&T,&&T;i32,&i32,&&i32
    &T T类型的引用(共享不可变的引用) &i32, &&i32
    &mut T T类型的可变引用(独占可变引用) &mut i32

    T类型是&T和&mut T的超集;

    “可变不共享,共享不可变”

    在Rust中一个变量的生命期是指其所指向的内存地址中数据有效的“一段时期”;而这段时期是有编译器静态分析得出的,有效性是由编译器保证的

    二、样例

    1、T 只包含所有权类型

    类型 T &T &mut T
    样例 i32 &i32 &mut i32

    其中T包含全体所有权类型;&T包括全体不可变引用;&mut T包括全体可变引用;
    其中T、&T、&mut T是不相交的有限集合

    实际情况如下

    类型 T &T &mut T
    例子 i32,&i32,&muti32,&&i32,&mut &mut i32,... &i32,&&i32,&&mut i32,... &mut i32, &mut &mut i32, &mut &i32,...

    T, &T, &mut T都是无限集合; T是&T和&mut T的超集(由于可引用类型T自身无限次),且&T和&mut T是不相交的集合

    trait TestTrait {}
    
    
    impl<T> TestTrait for T {}      // target-1
    
    
    impl<T> TestTrait for &T {}     // target-2
    
    
    impl<T> TestTrait for &mut T {} // target-3
    

    上述代码是不能编译通过的:

    error[E0119]: conflicting implementations of trait `TestTrait` for type `&_`
     --> src/bin/trait_generic_demo.rs:6:1
      |
    4 | impl <T> TestTrait for T{}
      | ------------------------ first implementation here
    5 | 
    6 | impl<T> TestTrait for &T {}
      | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_`
    

    所以验证了“T是&T和&mut T的超集”,也就意味着“target-1”的代码包括了“target-2”和“target-3”的实现;
    而若是注释掉“target-1”的代码,其他不变,则编译也是OK的,说明了“&T和&mut T是不相交的集合”

    2、若是 T:'static,那么T的生命周期就会直到程序结束为止都一定是有效的

    • T:'static 应视为T有着'static的生命周期 ???
    • &'static T和T:'static 是一回事 ???
    • 若T:'static 则T一定不可变的 ???
    • 若T: 'static 则只能编译期创建 ???
      当首次接触'static生命周期,更多是如下的例子
    let str_literal: &'static str = "字符串字面量";
    

    这里的“字符串字面量”会被硬编码到编译出来的二进制文件中,并在运行时被加载到只读内存中,在整个运行期间有效且不可变的,使其生命周期为'static。 ???

    举个例子:

    static strs: [&str; 3] = ["hello", "world", "yes"];
    static mut mut_strs: [&str; 3] = ["hello", "world", "yes"];
    
    fn main() {
        // 错误信息
        // error[E0594]: cannot assign to `strs[_]`, as `strs` is an immutable static item
        //  --> src/bin/static_var_demo.rs:7:5
        //   |
        // 7 |     strs[0] = "come_here";
        //   |     ^^^^^^^^^^^^^^^^^^^^^ cannot assign
        // strs[0] = "come_here";
        unsafe {
            mut_strs[0] = "come_here";
            assert_eq!("come_here", mut_strs[0]);
        }
    }
    

    从上面的示例中,得出关于静态变量

    • 只能在编译期创建
    • 默认情况下它们是不可变的,修改静态变量可通过unsafe
    • 在整个程序运行期间都有效
      那么静态变量的生命周期是不是就是'static? 具有'static生命周期的变量是否要遵守上述同样的规则?
      需要注意的的是带有'static生命周期注解的类型和一个被'static约束的类型是不一样的,后者是可以在运行时被动态分配的,能被安全的修改的,也可以被drop,其还能存活任意的时长;

    区分&'static T和 T: 'static:

    • &'static T是一个指向T的不可变引用,其中T可被安全的无限期地持有,甚至可直到程序结束;要求T自身不可变且保证在引用创建后不会被move; T也并不需要在编译时创建;
    • T:'static 是指T可以被安全地无限期地持有,甚至可以直到程序结束;T:'static 在包括了全部的&'static T的同时,还包括了所有权类型; 数据的所有者保证,只要自身还持有数据的所有权,数据就不会失效,这样所有者能够安全的无限期的持有数据,直至程序结束;此时T满足'static生命周期的约束而非T有着'static 生命周期;
    use rand;
    
    /// &'static T 样例
    fn  rand_str_generator() -> &'static str {
        let rand_str = rand::random::<u64>().to_string();
        Box::leak(rand_str.into_boxed_str()); // 存在“内存泄漏”
    }
    
    /// T: 'static样例
    fn drop_static<T: 'static>(t: T) {
        std::mem::drop(t);
    }
    
    fn drop_static_demo() {
        let mut strings: Vec<String> = Vec::new();
        for _ in 0..10 {
            if rand::random() {
                let string = rand::random::<u64>().to_string();
                strings.push(string);
            }
        }
    
        for mut string in strings {
            string.push_str(" a mutation");
            println!("{:?}", string);
            drop_static(string);
        }
    
        println!("i am the end of the program");
    }
    
    fn main() {
       // &'static T
       let rand_str = rand_str_generator();
        println!("{:?}", rand_str);
        // T: 'static 样例
        drop_static_demo();
    }
    

    关键点:

    • T: 'static 应当视为 “T 满足 'static 生命周期约束”
    • 若 T: 'static 则 T 可以是一个有 'static 生命周期的引用类型 或 是一个所有权类型
    • 因为 T: 'static 包括了所有权类型,所以 T
      1. 可以在运行时动态分配
      2. 不需要在整个程序运行期间都有效
      3. 可以安全,自由地修改
      4. 可以在运行时被动态的 drop
      5. 可以有不同长度的生命周期

    (待续)

    相关文章

      网友评论

        本文标题:关于Rust中常见的生命期的“例子”(一)

        本文链接:https://www.haomeiwen.com/subject/bmcwjrtx.html