关于解引用*操作符,谨供参考!

一、主要代码

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 :&String
         ref 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:&String
            MyBox(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: &String
    println!("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: &String
        let p = &**tmp; //p:&str
        println!("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);
            }
        }
    }
    // 模仿Cow
    enum 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:&String
        MyBox(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);

更多推荐