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
1
共 5 条评论, 1 页
评论区
写评论这里的msg_builder持有msg的可变引用,所以不能用
msg.check_it()
. 不过在for循环里面check msg的逻辑是不是需要再考虑下使用RefCell就可以了,解决可变引用和不可变引用的冲突。
URL: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=b85b7ee45040ed409d70ee9cc40298ad
--
👇
dzbjet: 是什么问题?
改成你简化后的代码,msg_builder的生命周期与msg的生命周期,哪个作为'a?
即在‘a的生命周期内,存在对msg的可变借用,因此不允许有不可变借用。
--
👇
Pikachu: 没看懂你要干什么,但是给你简化了一下代码
问题基本出在了
Box<dyn Fn() + 'a>
这里。是什么问题?
改成你简化后的代码,msg_builder的生命周期与msg的生命周期,哪个作为'a?
即在‘a的生命周期内,存在对msg的可变借用,因此不允许有不可变借用。
--
👇
Pikachu: 没看懂你要干什么,但是给你简化了一下代码
问题基本出在了
Box<dyn Fn() + 'a>
这里。没看懂你要干什么,但是给你简化了一下代码
问题基本出在了
Box<dyn Fn() + 'a>
这里。好长的代码而且还没注释。。。可以浓缩成一个简单的例子么?可变不可变冲突我个人觉得要不就是设计有问题,没看完无责任的说,可以试试RefCell之类的?