< 返回版块

dzbjet 发表于 2022-11-15 08:52

Tags:rust, mutable borrow, immutable borrow



use bytes::*;
use std::any::Any;

type Encoder<'a> = Box<dyn FnMut(&mut BytesMut) + 'a>;
type Decoder<'a> = Box<dyn FnMut(&mut Bytes) + 'a>;

pub trait IE {
    fn encode(ie: &Self, stream: &mut BytesMut)
    where
        Self: Sized;
    fn decode(stream: &mut Bytes) -> Self
    where
        Self: Sized;
    fn as_any(&self) -> &dyn Any;
}

#[derive(Debug, Clone, Copy)]
pub struct MyIEa {
    num: u32,
}

impl IE for MyIEa {
    fn decode(stream: &mut Bytes) -> Self
    where
        Self: Sized,
    {
        println!("MyIEa::decode");
        MyIEa {
            num: stream.get_u32(),
        }
    }

    fn encode(ie: &Self, stream: &mut BytesMut)
    where
        Self: Sized,
    {
        stream.put_u32(ie.num);
        println!("MyIEa::encode: {:?}", ie);
    }

    fn as_any(&self) -> &dyn Any {
        self
    }


}

pub trait SerialMsg {
    fn check_it(&self);
    fn on_build<'a: 'b, 'b>(&'a mut self, msg_builder: &mut MsgBuilder<'b>);
}

pub struct MsgA {
    ie_a: MyIEa,
}

impl SerialMsg for MsgA {
    fn on_build<'a: 'b, 'b>(&'a mut self, msg_builder: &mut MsgBuilder<'b>) {
        msg_builder.mandatory_ie(&mut self.ie_a);
    }

    fn check_it(&self) {
        let _ = self;
    }
}

pub struct MsgBuilder<'a> {
    pub msg_encoders: Vec<Encoder<'a>>,
    pub msg_decoders: Vec<Decoder<'a>>,

    pub msg_opt_encoders: Vec<Encoder<'a>>,
    pub msg_opt_decoders: Vec<Decoder<'a>>,
}

impl<'a> MsgBuilder<'a> {
    pub fn new() -> Self {
        MsgBuilder {
            msg_encoders: Vec::new(),
            msg_decoders: Vec::new(),

            msg_opt_encoders: Vec::new(),
            msg_opt_decoders: Vec::new(),
        }
    }

    pub fn mandatory_ie<X: IE + Clone + 'static>(&mut self, ie: &'a mut X) {
        let ie_cloned = ie.clone();

        // for encoder
        let encoder = move |stream: &mut BytesMut| {
            let t = ie_cloned
                .as_any()
                .downcast_ref::<X>()
                .expect("mandatory_ie, T:IE != ie: &mut dyn IE");
            X::encode(t, stream);
        };
        self.msg_encoders.push(Box::new(encoder));

        // for decoder
        let decoder = |stream: &mut Bytes| {
            let ie_x = X::decode(stream);
            ie.clone_from(&ie_x);
        };
        self.msg_decoders.push(Box::new(decoder));
    }

    pub fn optional_ie<X: IE + Clone + 'static>(&mut self, ie: &'a mut Option<X>) {
        if ie.is_some() {
            let ie = ie.clone().unwrap();

            // for encoder
            let encoder = move |stream: &mut BytesMut| {
                let t = ie
                    .as_any()
                    .downcast_ref::<X>()
                    .expect("optional_ie, T:IE != ie: &mut dyn IE");
                X::encode(t, stream);
            };
            self.msg_opt_encoders.push(Box::new(encoder));
        }

        // for decoder
        let decoder = |stream: &mut Bytes| {
            let ie_x = X::decode(stream);
            ie.clone_from(&Some(ie_x));
        };
        self.msg_opt_decoders.push(Box::new(decoder));
    }
}


fn test_ex17() {
    let mut msg = MsgA { ie_a: MyIEa { num: 100 }, };
    {
        let mut stream = Bytes::new();
        let mut stream_mut = BytesMut::new();

        let mut msg_builder = MsgBuilder::new();
        msg.on_build(&mut msg_builder);

        for mut decoder in msg_builder.msg_opt_decoders {
            decoder(&mut stream);
        }

        for mut encoder in msg_builder.msg_opt_encoders {
            msg.check_it();
            encoder(&mut stream_mut);
        }
    }
}


下面是给出的报错提示,主要是由于交叉引用,msg_builder持有对msg的可变引用?因此在其生命周期结束前,无法对msg做不可变借用?(msg.check_it())

该问题如何解决呢?

   Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `msg` as immutable because it is also borrowed as mutable
   --> src/lib.rs:146:13
    |
139 |         msg.on_build(&mut msg_builder);
    |         ------------------------------ mutable borrow occurs here
...
146 |             msg.check_it();
    |             ^^^^^^^^^^^^^^ immutable borrow occurs here
...
149 |     }
    |     - mutable borrow might be used here, when `msg_builder` is dropped and runs the destructor for type `MsgBuilder<'_>`

For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` due to previous error


Ext Link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=fc736f464d1e5b797cc370c6b825e72e

评论区

写评论
wangbyby 2022-11-15 23:07
for mut encoder in msg_builder.msg_opt_encoders {
            msg.check_it();
            encoder(&mut stream_mut);
}

这里的msg_builder持有msg的可变引用,所以不能用msg.check_it(). 不过在for循环里面check msg的逻辑是不是需要再考虑下

作者 dzbjet 2022-11-15 17:48

使用RefCell就可以了,解决可变引用和不可变引用的冲突。

URL: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=b85b7ee45040ed409d70ee9cc40298ad

#[test]
fn tmp_test() {
    use std::cell::*;

    pub struct MsgA(u32);

    #[derive(Default)]
    pub struct MsgBuilder<'a> {
        pub msg_encoders: Vec<Box<dyn Fn() + 'a>>,
    }

    impl<'a> MsgBuilder<'a> {
        pub fn mandatory_ie(&mut self, _ie: &'a RefCell<MsgA>) {
            _ie.borrow_mut().0 = 1000;
        }
    }

    let msg = RefCell::new(MsgA(0));
    
    let mut msg_builder = MsgBuilder::default();

    msg_builder.mandatory_ie(&msg);

    let _msg = msg.borrow();
    println!("{:?}", _msg.0);

}

--
👇
dzbjet: 是什么问题?

改成你简化后的代码,msg_builder的生命周期与msg的生命周期,哪个作为'a?

即在‘a的生命周期内,存在对msg的可变借用,因此不允许有不可变借用。

--
👇
Pikachu: 没看懂你要干什么,但是给你简化了一下代码

pub struct MsgA;

#[derive(Default)]
pub struct MsgBuilder<'a> {
    pub msg_encoders: Vec<Box<dyn Fn() + 'a>>,
}

impl<'a> MsgBuilder<'a> {
    pub fn mandatory_ie(&mut self, _ie: &'a mut MsgA) {}
}

fn main() {
    let mut msg = MsgA;

    let mut msg_builder = MsgBuilder::default();
    msg_builder.mandatory_ie(&mut msg);

    let _msg = &msg;
}

问题基本出在了Box<dyn Fn() + 'a>这里。

作者 dzbjet 2022-11-15 17:37

是什么问题?

改成你简化后的代码,msg_builder的生命周期与msg的生命周期,哪个作为'a?

即在‘a的生命周期内,存在对msg的可变借用,因此不允许有不可变借用。

--
👇
Pikachu: 没看懂你要干什么,但是给你简化了一下代码

pub struct MsgA;

#[derive(Default)]
pub struct MsgBuilder<'a> {
    pub msg_encoders: Vec<Box<dyn Fn() + 'a>>,
}

impl<'a> MsgBuilder<'a> {
    pub fn mandatory_ie(&mut self, _ie: &'a mut MsgA) {}
}

fn main() {
    let mut msg = MsgA;

    let mut msg_builder = MsgBuilder::default();
    msg_builder.mandatory_ie(&mut msg);

    let _msg = &msg;
}

问题基本出在了Box<dyn Fn() + 'a>这里。

Pikachu 2022-11-15 16:50

没看懂你要干什么,但是给你简化了一下代码

pub struct MsgA;

#[derive(Default)]
pub struct MsgBuilder<'a> {
    pub msg_encoders: Vec<Box<dyn Fn() + 'a>>,
}

impl<'a> MsgBuilder<'a> {
    pub fn mandatory_ie(&mut self, _ie: &'a mut MsgA) {}
}

fn main() {
    let mut msg = MsgA;

    let mut msg_builder = MsgBuilder::default();
    msg_builder.mandatory_ie(&mut msg);

    let _msg = &msg;
}

问题基本出在了Box<dyn Fn() + 'a>这里。

eweca-d 2022-11-15 10:53

好长的代码而且还没注释。。。可以浓缩成一个简单的例子么?可变不可变冲突我个人觉得要不就是设计有问题,没看完无责任的说,可以试试RefCell之类的?

1 共 5 条评论, 1 页