关于rust中常见trait (一)

关于Drop: std::ops::Drop

/// 当一个类型实现Drop trait就不能实现Clone trait
/// 当一个类型是Copy,那就意味着按位复制就可以创建一个新的独立拷贝
/// ```rust
/// fn drop(_x: T)  // 传参发生"转移(move)"
/// {
///   ...
/// }
/// ```
/// 以值传递的方式,从调用者那获取所有权,然后什么也不做;当_x离开作用域时rust就会drop它的值
///
#[test]
fn test_trait_drop_demo () {
    struct Application {
        name: String,
        data: Vec,
    }

    impl Drop for Application {
        fn drop(&mut self) {
            println!("==Dropping {}", self.name);
            if !self.data.is_empty() {
                print!("==data({})", self.data.join(","));
            }
            println!("");
        }
    }

    let mut app1 = Application {
        name: String::from("zeus"),
        data: vec![String::from("hello"), String::from("world")],
    };

    drop(app1);  // 当在此处手动进行drop操作时,会使得app1变成"未被初始化状态"
    // drop(app1);  // 第二次主动drop是不被允许的,因为此时app1处于"未被初始化状态";
    println!("===start===");
    app1 = Application {  // 当调用drop时,此时的app1变成"初始化"而不是进行内容的修改
        name: String::from("lucas"),
        data: vec![String::from("h"), String::from("w")],
    }; // app1修改前的内容 会被drop
    println!("===end===");

    println!("===华丽分割线===");
    let app3 ; // 可以声明变量,并将初始化操作放置在后面
    {
        let app2 = Application {
            name: "app2".to_string(),
            data: vec!["hello".to_string(), "world".to_string()],
        };

        let flag = true;

        // 当flag == true时 app3 = app2时 app2"持有"的内容发生了move(转译),最终的drop的"时机"是在函数的结束
        // 当flag == flase时 不存在app2内容发生move(转译), 故而drop发生在当前代码块结束的位置
        if flag == true {
            app3 = app2;
        }
    }// inner-block-end
    // 当app3未被初始化时 不需要进行drop
    // drop(app3);
    println!("Sproing! What was that? ");

} // outer-block-end; 修改app1的内容被drop

关于Sized: std::marker::Sized

/// 在rust中所有固定大小的类型都是实现了 std::marker::Sized trait;
/// 切记:rust为所有合适的类型自动实现了Sized trait,不需要用户来实现并且也不能自己实现;
/// Sized主要的作用也是唯一的作用,用作类型参数的约束:
/// - T: Sized的约束要求T是一个大小在编译期已知的类型
/// 不过Rust也存在一些大小不固定的类型:它们的值大小并不相同;
/// 比如字符串切片类型str、dyn类型(trait对象引用的目标)、struct中最后一个字段(也只能是最后一个字段)
/// 在Rust中不能在变量中存储大小不固定的值或者将它们用作参数传递; 
///  一个指向大小不固定的值的指针总是一个胖指针,占用两个字节:比如指向切片的指针 + 切片长度就对应str胖指针
///           一个trait对象 + 一个指向trait方法实现的vtable指针 对应 trait object
/// 
#[test]
fn test_sized_demo() {
    // sized用来标识当前类型在编译期间大小固定
    // ?sized代表类型大小固定或不固定,在编译期大小不固定
    //  T: ?Sized: 可以提供大小固定的类型;也可以提供大小固定的类型
    struct RcBox {
        ref_count: usize,
        value: T,
    }

    // T: ?Sized此时T为String,一个胖指针: buf指针 + 容量capacity + 长度length
    let boxed_lunch: RcBox = RcBox {
        ref_count: 1,
        value: "hello_world".to_string(),
    };

    // RcBox此时T是一个大小不固定的类型:实现Display trait的对象dyn Display
    // 直接使用RcBox类型是不被允许的,在编译期当前类型大小是不确定的,需要使用&RcBox
    // 这样就可以将一个引用&RcBox 转换为胖指针引用 &RcBox
    let boxed_displayable: &RcBox = &boxed_lunch;
    // println!("{:?}", boxed_displayable);
    //
    fn display(boxed: &RcBox) {
        println!("for your enjoyment: {}", &boxed.value);
    }

    // 当向函数传参时 隐式进行了类型转换
    display(&boxed_displayable);
}

引用

Drop
动态类型与固定类型

你可能感兴趣的:(关于rust中常见trait (一))