關于解引用*操作符,謹供參考!
一、主要代碼
use std::ops::Deref;
fn main() {model_1();model_2();model_3();model_4();model_5();model_6();model_7();model_8();model_9();
}
二、*操作符與常見的引用和解引用
fn model_1(){let reference:&String = &String::from("hello");match *reference {// val :&Stringref val => println!("通過解引用和重新借用獲得的值: {:?}", val),}
}
如果沒有ref會如何?自行試一下,便知。
三、*操作符與match和Deref的簡單組合
fn model_2(){model_2_1();model_2_2();model_2_3();fn model_2_1(){let mybox = MyBox::new(String::from("hello world"));//*mybox: String */match *mybox {ref val => println!("通過解引用和重新借用獲得的值: {:?}", val),}println!("mybox:{:?}",mybox);}// 為什么這里不能是&MyBox(val),只能是MyBox(val)? 感覺類型不匹配呀!fn model_2_2(){let mybox = MyBox::new(String::from("hello world"));let ref_mybox = &mybox;// ref_mybox: &MyBox<String>match ref_mybox {//val:&StringMyBox(val) => println!("通過解引用和重新借用獲得的值: {:?}", val),// error//&MyBox(val) => println!("通過解引用和重新借用獲得的值: {:?}", val),}}// 解引用的找開方式fn model_2_3(){let value = MyBox::new(String::from("hello world"));model_2_3_1(&value);fn model_2_3_1(value : &MyBox<String>){match *value {//val: &MyBox<String>ref val=> println!("通過解引用和重新借用獲得的值: {:?}", val),// error//&MyBox(val) => println!("通過解引用和重新借用獲得的值: {:?}", val),// error//MyBox(val) => println!("通過解引用和重新借用獲得的值: {:?}", val),}}}use std::ops::Deref;#[derive(Debug)]struct MyBox<T>(T);impl<T> Deref for MyBox<T> {type Target = T;fn deref(&self) -> &Self::Target {&self.0}}impl<T: std::fmt::Debug> MyBox<T> {fn new(x: T) -> MyBox<T> {MyBox(x)}fn my_print(&self) {match self {MyBox(x) => println!("{:?}", x),}}}
}
四、*操作: move 所有權的情況
需要注意的是,*操作可能會move所有權,需要慎重。當然也有一些特別情況。后面會具體補充說明。
fn model_3(){let vec = vec![1, 2, 3];let v_tmp = &vec; // v_tmp:只是借引用,沒有解引用(轉移所有權)的權力//let v_p = *v_tmp; // 去掉注釋將報錯,error: 轉移所有權println!("vec:{:?}", v_tmp);
}
// *操作: move 所有權
fn model_4(){let raw = Box::new(String::from("hello world"));let tmp = *raw; // tmp: String//println!("raw:{:?}", raw); // 去掉注釋將報錯,error: 此時raw is moved!let p = &tmp; // p: &Stringprintln!("box:{:?}", p);}
// 請問一下:MyBox為什么不可以和Box一樣操作?
fn model_5(){model_5_1();model_5_2();fn model_5_1(){let raw = MyBox::new(String::from("hello world"));// 下面注釋代碼一起取消將報錯:error//let tmp = *raw; //let p = &tmp;//println!("box:{:?}", p);let p = &*raw; // p: &String ;此時和分開操作不一樣println!("p:{:?}",p);}fn model_5_2(){let value = String::from("hello world"); let raw = MyBox::new(&value); //raw:MyBox<&String>let tmp = *raw; // tmp: &Stringlet p = &**tmp; //p:&strprintln!("box:{:?}", p);}struct MyBox<T>(T);impl<T> MyBox<T> {fn new(x: T) -> MyBox<T> {MyBox(x)}}impl <T> Deref for MyBox<T> {type Target = T;fn deref(&self) -> &Self::Target {&self.0}}
}
五、 *操作符用于賦值
fn model_6(){let mut p = String::from("hello world");//非 copy 類型let mut_p = &mut p; // mut_p: &mut String *mut_p = String::from("Hello World");println!("mut_p:{:?}", mut_p);
}
六、*操作符與match搭配的復雜情況
1、match與字段進行ref 或ref mut組合搭配
這種情況,不會move所有權。
fn model_7(){println!("下面是源碼,謹供參考!")//https://doc.rust-lang.org/src/alloc/borrow.rs.html// impl<B: ?Sized + ToOwned> Clone for Cow<'_, B> {// fn clone(&self) -> Self {// match *self {// Borrowed(b) => Borrowed(b),// Owned(ref o) => {// let b: &B = o.borrow();// Owned(b.to_owned())// }// }// }// }
}
2、match與"_"搭配
“_”和ref等一樣,是個特別的符號。不會move所有權。
fn model_8(){println!("下面是源碼,謹供參考!");// *self: 為什么可以直接解引用?*self: 字段中沒有ref,但有“_”,也可以//https://doc.rust-lang.org/src/alloc/borrow.rs.html// impl<B: ?Sized + ToOwned> Cow<'_, B> {// pub const fn is_borrowed(&self) -> bool {// match *self {// Borrowed(_) => true,// Owned(_) => false,// }// }// pub fn to_mut(&mut self) -> &mut <B as ToOwned>::Owned {// match *self {// Borrowed(borrowed) => {// *self = Owned(borrowed.to_owned());// match *self {// Borrowed(..) => unreachable!(),// Owned(ref mut owned) => owned,// }// }// Owned(ref mut owned) => owned,// }// }// } }fn model_9(){use std::borrow::Borrow;use std::ops::Deref;let dog = Dog::Borrowed("hello world");model_9_1(&dog);model_9_2(&dog);// *dog: 字段中沒有ref,但有“_”,也可以fn model_9_1(dog: &Dog<'_,str>){match *dog{Dog::Borrowed(_) => {println!("A");}Dog::Owned(_) => {println!("B");}}}// 少了ref,將報錯!fn model_9_2(dog: &Dog<'_,str>){match *dog{Dog::Borrowed(_) => {println!("A");}Dog::Owned(ref own) => {println!("B :{:?}",own);}}}// 模仿Cowenum Dog<'a,B:?Sized+'a> where B: ToOwned{Borrowed(&'a B),Owned( <B as ToOwned>::Owned),}impl<B: ?Sized + ToOwned> Deref for Dog<'_, B> where B::Owned: Borrow<B>,{type Target = B;fn deref(&self) -> &B {match *self {Dog::Borrowed(borrowed) => borrowed,Dog::Owned(ref owned) => owned.borrow(),}}}
}
七、問題
1、類型匹配
在model_2_2()中,為什么這里不能是&MyBox(val),只能是MyBox(val)?
fn model_2_2(){let mybox = MyBox::new(String::from("hello world"));let ref_mybox = &mybox;// ref_mybox: &MyBox<String>match ref_mybox {//val:&StringMyBox(val) => println!("通過解引用和重新借用獲得的值: {:?}", val),// error//&MyBox(val) => println!("通過解引用和重新借用獲得的值: {:?}", val),}
}
為什么上面會用MyBox(val)和匹配&MyBox< String>?思考一下。
2、Box和MyBox的操作的差異
具體在model_4和model_5中。Box可以進行先*后&的分開操作,而MyBox不可以。
具體的不同在于Box中是Unique< T>,而不是和MyBox中T 。
// 說明:Box源碼如下: // pub struct Box<T: ?Sized, A: Allocator = Global>(Unique<T>, A);