[−][src]Function tao_of_rust::ch13::security_abstract::variances
pub fn variances()
子类型和型变(variance)
PhantomData
PhantomData
请配合书本中解释理解
Basic usage: 未合理使用型变将会引起未定义行为
虽然可以正常工作,但这里存在未定义行为的风险 原因是协变改变了生命周期,「忽悠」了借用检查
// 协变类型 struct MyCell<T> { value: T, } impl<T: Copy> MyCell<T> { fn new(x: T) -> MyCell<T> { MyCell { value: x } } fn get(&self) -> T { self.value } fn set(&self, value: T) { use std::ptr; unsafe { ptr::write(&self.value as *const _ as *mut _, value); } } } fn step1<'a>(r_c1: &MyCell<&'a i32>) { let val: i32 = 13; step2(&val, r_c1); // step2函数执行完再回到step1 println!("step1 value: {}", r_c1.value); } // step1调用完,栈帧将被清理,val将不复存在,&val将成为悬垂指针 fn step2<'b>(r_val: &'b i32, r_c2: &MyCell<&'b i32>) { r_c2.set(r_val); } static X: i32 = 10; fn main() { let cell = MyCell::new(&X); step1(&cell); println!(" end value: {}", cell.value); //此处 cell.value的值将无法预期,UB风险 }Run
Basic usage: 修改MyCell
解决上面示例UB的问题,编译将报错,因为安全检查生效了,成功阻止了UB风险
use std::marker::PhantomData; struct MyCell<T> { value: T, mark: PhantomData<fn(T)> , //通过PhantomData<fn(T)>将MyCell<T>改为逆变类型 } impl<T: Copy> MyCell<T> { fn new(x: T) -> MyCell<T> { MyCell { value: x , mark: PhantomData} } fn get(&self) -> T { self.value } fn set(&self, value: T) { use std::ptr; unsafe { ptr::write(&self.value as *const _ as *mut _, value); } } } fn step1<'a>(r_c1: &MyCell<&'a i32>) { let val: i32 = 13; step2(&val, r_c1); // error[E0597]: `val` does not live long enough println!("step1 value: {}", r_c1.value); } // step1调用完,栈帧将被清理,val将不复存在,&val将成为悬垂指针 fn step2<'b>(r_val: &'b i32, r_c2: &MyCell<&'b i32>) { r_c2.set(r_val); } static X: i32 = 10; fn main() { let cell = MyCell::new(&X); step1(&cell); println!(" end value: {}", cell.value); }Run
Basic usage: fn(T)逆变示意
Rust中仅存在函数指针fn(T)的逆变情况
请配合书本解释理解
trait A { fn foo(&self, s: &'static str); } struct B; impl A for B { fn foo(&self, s: &str){ println!("{:?}", s); } } impl B{ fn foo2(&self, s: &'static str){ println!("{:?}", s); } } fn main() { B.foo("hello"); // let s = "hello".to_string(); // B.foo2(&s) }Run
Basic usage: 另一个fn(T)逆变示意
Rust中仅存在函数指针fn(T)的逆变情况
请配合书本解释理解
fn foo(input: &str) { println!("{:?}", input); } fn bar(f: fn(&'static str), v: &'static str) { (f)(v); } fn main(){ let v : &'static str = "hello"; bar(foo, v); }Run