Reputation: 293
I have a System, which will connect multiply API downstreams. I would like to use
let mut system = System::new()
to intake config and do the validation, then use
system.init()
to init all connections for the downstreams.
After it connects all downstreams, I would like to make multiple methods to do CRUD to the downstreams.
Here's the playground
struct Conn {
connection: String,
}
impl Conn {
fn fetch(&mut self) -> &str {
self.connection.push_str("data");
&self.connection
}
}
struct System {
downstream: Option<Conn>,
}
impl System {
fn new() -> Self {
System { downstream: None }
}
fn init(&mut self) {
self.downstream = Some(Conn {
connection: String::from("db connection"),
})
}
fn method_a(self) -> String {
let mut conn = self.downstream.unwrap();
String::from(conn.fetch())
}
fn method_b(self) -> String {
let mut conn = self.downstream.unwrap();
String::from(conn.fetch())
}
}
fn main() {
let mut system = System::new();
system.init();
println!("{}", system.method_a());
println!("{}", system.method_b());
}
However, because system.method_a()
moved the ownership at unwrap()
, so when I call the second method system.method_b()
after the first one. Obviously, I will get the error "use of moved value".
I understand how and why the error happens. But I don't know what's the idiomatic way to deal with this situation.
One workaround way is use Conn
instead of Option<Conn>
, but if don't use Option, then I have to init all downstream connections in System.new()
and all downstreams can't have the value of "None".
So my question is how I design a module to fix my purpose?
Thanks in advance.
Upvotes: 2
Views: 849
Reputation: 6779
In the example you provided, you could change method_a
and method_b
to take a mutable reference instead. conn
itself just calls fetch()
which uses mutable ref.
fn method_a(&mut self) -> String {
self.downstream
.as_mut()
.map(|conn| String::from(conn.fetch()))
.unwrap()
}
fn method_b(&mut self) -> String {
self.downstream
.as_mut()
.map(|conn| String::from(conn.fetch()))
.unwrap()
}
For undertanding purposes, you could also write the above method as:
fn method_a(&mut self) -> String {
match self.downstream {
Some(ref mut conn) => String::from(conn.fetch()),
None => panic!(),
}
}
And if the above code is just an example snippet and you need ownership of conn
for some reason, you can do it by take()
and if that also doesn't work then you will have to make your struct implement Clone
trait so you can clone it instead of moving.
Upvotes: 8