Reputation: 13
Warning, very novice Rust coder here. I'm sure this is just a basic misunderstanding of how ownership works on my end but i cant seem to wrap my head around why this code runs into error[E0502]: cannot borrow self.bids
as mutable because it is also borrowed as immutable.
UPDATE: have changed the code snippet to something reproducible.
fn main() {
#[derive(Debug, Default)]
struct OrderBook {
bids: Vec<Order>
}
#[derive(Debug)]
struct Order {
price: f64,
quantity: i64,
}
impl OrderBook {
pub fn add_order(&mut self, order: Order) -> Result<(), &str> {
match self.orderbook_checks() {
Ok(_) => {
self.bids.push(order);
Ok(())
}
Err(e) => Err(e),
}
}
pub fn orderbook_checks(&self) -> Result<(), &str> {
Err("error message")
}
}
let mut order_book = OrderBook::default();
let price: f64 = 10.0;
let quantity: i64 = 100;
let order = Order { price, quantity };
order_book.add_order(order);
}
I would think that the borrow of self in the Ok() arm of the match statement on "checks" will only happen when checks evaluates to Ok() and in the event of Err(e) it should be allright to return Err(e). However this code only compiles when I return a string literal and not when using the error message value e like i do in the code snippet.
Hope anyone of you wants enlighten me on what is wrong in my thinking. I have taken a look at similar questions but I cant figure it out yet.
Compiler output below.
error[E0502]: cannot borrow `self.bids` as mutable because it is also borrowed as immutable
--> src/main.rs:16:21
|
13 | pub fn add_order(&mut self, order: Order) -> Result<(), &str> {
| - let's call the lifetime of this reference `'1`
14 | match self.orderbook_checks() {
| ----------------------- immutable borrow occurs here
15 | Ok(_) => {
16 | self.bids.push(order);
| ^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
...
19 | Err(e) => Err(e),
| ------ returning this value requires that `*self` is borrowed for `'1`
Upvotes: 1
Views: 154
Reputation: 8678
This error stems from the fact that you have not explicitly annotated the lifetimes, and therefore Rust figures out on itself some lifetimes that do not work. This is because, in a method like fn orderbook_checks(&self) -> Result<(), &str>
, without lifetime annotations, Rust gives the same lifetime to &self
and to &str
which is, when you think about it, completely false: the &str
returned does not depend on &self
being still valid. That is, it is equivalent to fn orderbook_checks<'a>(&'a self) -> Result<(), &'a str>
.
In fact, in your example, since all strings are hard-coded, you could simply given them a 'static
lifetime:
fn main() {
#[derive(Debug, Default)]
struct OrderBook {
bids: Vec<Order>
}
#[derive(Debug)]
struct Order {
price: f64,
quantity: i64,
}
impl OrderBook {
pub fn add_order(&mut self, order: Order) -> Result<(), &'static str> {
match self.orderbook_checks() {
Ok(_) => {
self.bids.push(order);
Ok(())
}
Err(e) => Err(e),
}
}
pub fn orderbook_checks(&self) -> Result<(), &'static str> {
Err("error message")
}
}
let mut order_book = OrderBook::default();
let price: f64 = 10.0;
let quantity: i64 = 100;
let order = Order { price, quantity };
order_book.add_order(order);
}
See the playground.
This works because, now, when you call self.orderbook_checks()
, Rust doesn't have to borrow self
for as much as the &str
you could return would have to live; which, because of the same rule, is the same as &mut self
in add_order(&mut self, order: Order) -> Result<(), &str>
.
Upvotes: 1