关于Drop: std::ops::Drop
/// 当一个类型实现Drop trait就不能实现Clone trait
/// 当一个类型是Copy,那就意味着按位复制就可以创建一个新的独立拷贝
/// ```rust
/// fn drop<T>(_x: T) // 传参发生"转移(move)"
/// {
/// ...
/// }
/// ```
/// 以值传递的方式,从调用者那获取所有权,然后什么也不做;当_x离开作用域时rust就会drop它的值
///
#[test]
fn test_trait_drop_demo () {
struct Application {
name: String,
data: Vec<String>,
}
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<T: ?Sized> {
ref_count: usize,
value: T,
}
// T: ?Sized此时T为String,一个胖指针: buf指针 + 容量capacity + 长度length
let boxed_lunch: RcBox<String> = RcBox {
ref_count: 1,
value: "hello_world".to_string(),
};
// RcBox<dyn Display>此时T是一个大小不固定的类型:实现Display trait的对象dyn Display
// 直接使用RcBox<dyn Display>类型是不被允许的,在编译期当前类型大小是不确定的,需要使用&RcBox<dyn Display>
// 这样就可以将一个引用&RcBox<String> 转换为胖指针引用 &RcBox<dyn Display>
let boxed_displayable: &RcBox<dyn Display> = &boxed_lunch;
// println!("{:?}", boxed_displayable);
//
fn display(boxed: &RcBox<dyn Display>) {
println!("for your enjoyment: {}", &boxed.value);
}
// 当向函数传参时 隐式进行了类型转换
display(&boxed_displayable);
}
引用
Drop
动态类型与固定类型