关于解引用*操作符,谨供参考!
一、主要代码
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);