I'm newish to Rust and I'm trying to figure out how to fix the Trader.gateway_client method in the snippet below. It is caused by a double borrow of a mutable. What would be the correct way to fix the code (without cloning the self.gateway string before).
use std::collections::{HashMap};
pub struct GatewayClient {
gateway: String,
strategy: String,
}
pub struct Trader {
gateway_clients: HashMap<String, GatewayClient>,
strategy: String,
}
impl GatewayClient {
pub fn new(gateway: &str, strategy: &str) -> Self {
GatewayClient {
gateway: String::from(gateway),
strategy: String::from(strategy),
}
}
}
impl Trader {
pub fn new(strategy: &str) -> Self {
Trader {
gateway_clients: HashMap::default(),
strategy: String::from(strategy),
}
}
pub fn gateway_client(&mut self, gateway: &str) -> &mut GatewayClient {
self.gateway_clients.entry(String::from(gateway)).or_insert_with(|| {
GatewayClient::new(gateway, &self.strategy)
})
}
}
The error thrown by the compiler is
63 | pub fn gateway_client(&mut self, gateway: &str) -> &mut GatewayClient {
| - let's call the lifetime of this reference `'1`
64 | self.gateway_clients.entry(String::from(gateway)).or_insert_with(|| {
| -------------------- ^^ immutable borrow occurs here
| |
| _________mutable borrow occurs here
| |
65 | | GatewayClient::new(gateway, &self.strategy)
| | ------------- second borrow occurs due to use of `self` in closure
66 | | })
| |__________- returning this value requires that `self.gateway_clients` is borrowed for `'1`
A way to get around the borrowing conflict would be to eliminate the second explicit borrow within the callback by extracting what you need from self outside of it.
pub fn gateway_client(&mut self, gateway: &str) -> &mut GatewayClient {
let strategy = &self.strategy;
self.gateway_clients
.entry(gateway.into())
.or_insert_with(|| GatewayClient::new(gateway, strategy))
}
This looks like it may be a second borrow against self within the callback, but the compiler accepts this.
.or_insert_with() vs. .or_insert()
A fix was suggested using .or_insert(), but your choice to use .or_insert_with() is correct.
The advantage of using .or_insert_with() over .or_insert() in this case is the callback only gets executed if the entry doesn't exist. If using .or_insert(), GatewayClient::new() would be invoked whether or not the entry existed every time.
You just didn't need to use .or_insert_with which allows to execute custom code via a closure. You just wanted to insert a value, and there's a method .or_insert, that accepts a value.
pub fn gateway_client(&mut self, gateway: &str) -> &mut GatewayClient {
self.gateway_clients
.entry(gateway.to_string())
.or_insert(GatewayClient::new(gateway, &self.strategy))
}
Also if you'll ever want to get rid of a million of creations of new strings with String::from(...), you can look towards std::borrow::Cow type
Related
This question already has an answer here:
Why is there a borrow of a moved value when calling a method that takes self by value with an argument that also calls a method?
(1 answer)
Closed last year.
The below rust code has compilation error.
struct Builder;
impl Builder {
pub fn add(&mut self, id: i32) -> i32 {
id + 1
}
}
fn main() {
let mut b = Builder;
b.add(b.add(10));
}
error[E0499]: cannot borrow `b` as mutable more than once at a time
--> examples/mutable_borrow_at_a_time.rs:10:11
|
10 | b.add(b.add(10));
| - --- ^ second mutable borrow occurs here
| | |
| | first borrow later used by call
| first mutable borrow occurs here
Unlike the question Cannot borrow `x` as mutable more than once at a time, add does not return any reference at all.
Unlike the question Borrow errors for multiple borrows, the return type is i32 which has 'static lifetime.
While the following code can be compiled without errors.
struct Builder;
impl Builder {
pub fn add(&mut self, id: i32) -> i32 {
id + 1
}
}
fn main() {
let mut b = Builder;
let x = b.add(10);
b.add(x);
}
Anyway it is cumbersome to create a dummy variable x every time for a compound expression.
First there will be a mutable borrow on the outer b.add(...) and then there will be an attempt to make a second mutable borrow on the inner b.add(). That is wonderfully explained & visualized by the compiler in the error message that you pasted:
| b.add(b.add(10));
| - --- ^ second mutable borrow occurs here
| | |
| | first borrow later used by call
| first mutable borrow occurs here
This limitation might be removed at some point, but for now, that's how it works.
And for your specific example, as Jmb mentioned, you don't need mut at all, so this will work just fine:
struct Builder;
impl Builder {
pub fn add(&self, id: i32) -> i32 {
id + 1
}
}
fn main() {
let b = Builder;
b.add(b.add(10));
}
It looks like you are attempting to use the builder pattern.
The difficulty stands in passing a &mut on the builder from call to call.
Each step in the chain should rather consume the previous state of the builder and emit a new state (like add() here).
Finally, the last step (build()) consumes the builder for the last time and emits instead the value we intended to build.
You might be worried about the performance cost of these multiple move/consume operations (instead of altering through a &mut), but when enabling optimizations, the compiler is able to look through these calls and can decide to do everything in place: a function only containing Builder::new().add(10).add(20).build() produces mov eax, 30 ret.
struct Builder {
id: i32,
}
impl Builder {
pub fn new() -> Self {
Builder { id: 0 }
}
pub fn add(
mut self,
incr: i32,
) -> Self {
self.id += incr;
self
}
pub fn build(self) -> i32 {
self.id
}
}
fn main() {
let id = Builder::new().add(10).add(20).build();
println!("id={:?}", id);
}
I am writing a tool that generates Rust code, and I've come up with the following pattern that is being generated:
pub fn my_template() {
let mut o = HtmlGenerator::new();
o.paragraph(&mut || {
o.emphasis(&mut || {
o.normal_text("hello");
});
});
}
The paragraph and emphasis methods have the type:
fn paragraph(&mut self, cnt: &mut impl FnMut());
I get the following error:
|
197 | o.paragraph(&mut || {
| ^ --------- -- first mutable borrow occurs here
| | |
| _________| first borrow later used by call
| |
198 | | o.normal_text("hello");
| | - first borrow occurs due to use of `o` in closure
199 | | });
| |__________^ second mutable borrow occurs here
Apparently I cannot borrow the mutable reference twice. It needs to be mutable because some of the generator functions might change the state of the HtmlGenerator, which is why I use methods in the first place.
Can this pattern be implemented in Rust? Am I trying to create nonsense?
The pattern cannot be implemented with exactly the provided signatures of paragraph() and other methods. But it's possible to get the same effect with just minor changes to either the closure signature or the method signatures.
The simplest and cleanest solution would be to pass the HtmlGenerator to the closures:
struct HtmlGenerator {
data: String,
}
impl HtmlGenerator {
fn new() -> HtmlGenerator {
HtmlGenerator {
data: "".to_string(),
}
}
fn paragraph(&mut self, inside: impl FnOnce(&mut HtmlGenerator)) {
self.data.push_str("<p>");
inside(self);
self.data.push_str("</p>");
}
fn normal_text(&mut self, text: &str) {
self.data.push_str(text);
}
fn into_data(self) -> String {
self.data
}
}
Playground
An alternative is to leave the closure signature as-is, but use interior mutability to make methods like paragraph() accept &self, at a very tiny run-time cost. For example:
struct HtmlGenerator {
data: RefCell<String>,
}
impl HtmlGenerator {
fn new() -> HtmlGenerator {
HtmlGenerator {
data: RefCell::new("".to_string()),
}
}
fn paragraph(&self, inside: impl FnOnce()) {
self.data.borrow_mut().push_str("<p>");
inside();
self.data.borrow_mut().push_str("</p>");
}
fn normal_text(&self, text: &str) {
self.data.borrow_mut().push_str(text);
}
fn into_data(self) -> String {
self.data.into_inner()
}
}
Playground
It may appear wrong to modify the data from an "immutable" method, but &self just means that the data is safe to share. self.data.borrow_mut() will panic if the borrow is already active, but that can't happen in the above code because the borrow is released as soon as the underlying data is modified. If we were to hold on to the guard returned by borrow_mut() and invoke the closure with the guard object live, the inner borrow_mut() in normal_text() invoked by the closure would panic.
In both approaches the trait bound for the closures can be the most permissive FnOnce, as the methods only invoke them once.
My question now is whether this pattern can even be ipmlemented in rust or whether I'm trying to create nonsense here?
It can't work like this, because the closure closes over the generator in order to implement the inner call, so the closure and the caller's borrow will necessarily overlap, which can not work.
What can work is for the generator methods to pass in the generator instance to the closures they call:
pub fn my_template() {
let mut o = HtmlGenerator::new();
o.paragraph(|o: &mut HtmlGenerator| {
o.emphasis(|o: &mut HtmlGenerator| {
o.normal_text("hello");
});
});
or something like that.
I also think you're probably better off passing the callable by value:
fn paragraph(&mut self, mut cnt: impl FnMut());
This question already has answers here:
Why can't I store a value and a reference to that value in the same struct?
(4 answers)
Closed 2 years ago.
I am writing a little Cards Against Humanity clone for personal use and am using it as a chance to learn Rust. I currently have the following structs:
// game.rs
pub struct Game<'c> {
deck: Deck,
players: Vec<Player<'c>>,
current_czar_index: usize,
}
// player.rs
pub struct Player<'c> {
pub hand: Vec<&'c Card>,
pub max_hand_size: usize,
pub is_czar: bool,
pub score: u8,
pub name: String,
}
// deck.rs
struct DiscardPile {
pub white: Mutex<Vec<usize>>,
pub black: Mutex<Vec<usize>>,
}
pub struct Deck {
white: Vec<Card>,
black: Vec<Card>,
pub used_sets: Vec<String>,
discard_pile: DiscardPile,
}
// card.rs
pub struct Card {
pub text: String,
pub uuid: Uuid,
pub pick: Option<u8>,
}
There are a few others (namely set which is used for reading in JSON files), but they aren't relevant.
I have a function in game.rs
pub fn deal_hands(&self) -> Result<(), Box<dyn std::error::Error>> {
for player in &mut self.players {
while player.hand.len() < player.max_hand_size {
player.add_card(self.deck.draw_white().unwrap())?;
}
}
Ok(())
}
that is giving me the following error:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/game.rs:42:31
|
42 | player.add_card(self.deck.draw_white().unwrap())?;
| ^^^^^^^^^^
|
It specifically says that it is expecting &mut Player<'_> but found a lifetime of &mut Player<'c>.
HERE if you want to see the code firsthand.
How do I fix such a lifetime error, or do I need to rethink my architecture?
The architecture seems fine to me. You are probably just missing the passing of a lifetime parameter somewhere.
I'm not totally certain, but I believe issue may be that .draw_white() is returning Option<&Card> and it's not clear what the lifetime of the contained Card should be. I believe it is the case that anytime you return a borrowed value, you must attach a lifetime to the borrowed value. Otherwise, the borrow checker cannot tell how long the borrowed value will live.
Maybe try the following definition for .draw_white() instead
pub fn draw_white<'a>(&self) -> Option<&'a Card> {
You will then need to tweak deal_hands() to be something like the following. (Working on figuring out the right syntax, but I think it's something like this.)
pub fn deal_hands(&self) -> Result<(), Box<dyn std::error::Error>> {
for player<'c> in &mut self.players {
while player.hand.len() < player.max_hand_size {
player.add_card(self.deck.draw_white<'c>().unwrap())?;
}
}
Ok(())
}
I think I got it sorted out. Luckily everything builds just fine after pushing through a handful of errors.
Original Error
Ok. Here is the full error I saw when I tried to build your crate.
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/game.rs:42:31
|
42 | player.add_card(self.deck.draw_white().unwrap())?;
| ^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 39:2...
--> src/game.rs:39:2
|
39 | pub fn deal_hands(&self) -> Result<(), Box<dyn std::error::Error>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src/game.rs:42:21
|
42 | player.add_card(self.deck.draw_white().unwrap())?;
| ^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'c` as defined on the impl at 20:6...
--> src/game.rs:20:6
|
20 | impl<'c> Game<'c> {
| ^^
note: ...so that the types are compatible
--> src/game.rs:42:12
|
42 | player.add_card(self.deck.draw_white().unwrap())?;
| ^^^^^^^^
= note: expected `&mut Player<'_>`
found `&mut Player<'c>`
It looks like the problem is actually with deal_hands(). Rather than allowing the lifetime of &self to be elided, you need to specify the lifetime as &'c mut self. (The mut is because you are mutating self.players.) I'm not totally sure why Rust doesn't elide the lifetime of self to 'c, but that's probably another topic.
Next Error
The next error I ran into was
error: captured variable cannot escape `FnMut` closure body
--> src/game.rs:106:17
|
106 | .map(|num| player.play_card_by_index(num as usize))
| - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a reference to a
captured variable which escapes the closure body
| |
| inferred to be a `FnMut` closure
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
= note: ...therefore, they cannot allow references to captured variables to escape
For this one, the problem is actually not in the error message. You need to specify the lifetime of Card in the return value of .play_card_by_index() because otherwise it's not clear that the reference to Card actually outlives the closure. This means you need to adjust .play_card_by_index() to return &'c Card' instead of &Card`.
Final Error
There was a trivial error in your .get_player_names(). You just need to use .iter() instead of .into_iter() because the former will not take ownership of self. Also, you probably want to .clone() the player names too for a similar reason.
Full Diff
Here's the full diff
diff --git a/src/game.rs b/src/game.rs
index 573d09d..5ccbf6b 100644
--- a/src/game.rs
+++ b/src/game.rs
## -36,7 +36,7 ## impl<'c> Game<'c> {
/// Hands need to be filled on every turn, so this lets us fill everyones'
/// hands at once.
- pub fn deal_hands(&self) -> Result<(), Box<dyn std::error::Error>> {
+ pub fn deal_hands(&'c mut self) -> Result<(), Box<dyn std::error::Error>> {
for player in &mut self.players {
while player.hand.len() < player.max_hand_size {
player.add_card(self.deck.draw_white().unwrap())?;
## -124,7 +124,10 ## impl<'c> Game<'c> {
}
pub fn get_player_names(&self) -> Vec<String> {
- self.players.into_iter().map(|player| player.name).collect()
+ self.players
+ .iter()
+ .map(|player| player.name.clone())
+ .collect()
}
}
diff --git a/src/player.rs b/src/player.rs
index 4bd6848..9f95373 100644
--- a/src/player.rs
+++ b/src/player.rs
## -46,7 +46,7 ## impl<'c> Player<'c> {
/// Used in the TUI, we can play a card by index and get the reference
/// to the card we played
- pub fn play_card_by_index(&mut self, index: usize) -> & Card {
+ pub fn play_card_by_index(&mut self, index: usize) -> &'c Card {
self.hand.remove(index)
}
## -56,7 +56,7 ## impl<'c> Player<'c> {
/// instead of making the card on the client and sending the full card info,
/// we can just send the UUID[s] of the cards that were played with some
/// data about the order they were played in.
- pub fn play_card_by_uuid(&mut self, uuid: Uuid) -> Option<& Card> {
+ pub fn play_card_by_uuid(&mut self, uuid: Uuid) -> Option<&Card> {
// TODO: Find a better way to do this
let mut index_of_card: usize = self.hand.len() + 1;
for (index, card) in self.hand.iter().enumerate() {
Good Luck!
This looks like a fun project. I hope you continue to build it in Rust!
I am learning Rust. For my first program, I wrote this code to maintain data about a partial ordering:
use std::collections::{HashMap, HashSet};
struct Node {
num_before: usize,
successors: HashSet<String>,
}
impl Node {
fn new() -> Node {
Node {
num_before: 0,
successors: HashSet::new(),
}
}
}
pub struct PartialOrdering {
node: HashMap<String, Node>,
}
impl PartialOrdering {
pub fn new() -> PartialOrdering {
PartialOrdering {
node: HashMap::new(),
}
}
pub fn get_node(&mut self, name: &String) -> &mut Node {
self.node.entry(name.clone()).or_insert_with(Node::new)
}
pub fn add_order(&mut self, before: &String, after: &String) {
let mut before_node = self.get_node(before);
if after != before {
let mut after_node = self.get_node(after);
if before_node.successors.insert(after.clone()) {
after_node.num_before += 1;
}
}
}
}
Compiling this code produces this error:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> main.rs:35:25
|
33 | let before_node = self.get_node(before);
| ---- first mutable borrow occurs here
34 | if after != before {
35 | let mut after_node = self.get_node(after);
| ^^^^ second mutable borrow occurs here
36 | if before_node.successors.insert(after.clone()) {
| ---------------------- first borrow later used here
Admittedly I am new to the Rust borrowing rules, but this problem has me stumped. Please tell me what I am doing wrong, and how can I fix it?
The problem is that in Rust it is forbidden to take more than one mutable reference (&mut) to an object at a time (see here for details). Your get_node() takes &mut self and uses it to obtain an &mut Node contained in self (where self is a PartialOrdering). This causes the mutable borrow of self to exist for as long as the value returned by get_node() exists, preventing other calls to get_node(). This means that you can't have before_node: &mut Node and after_node: &mut Node in the same scope, unfortunately.
This question already has an answer here:
Linking the lifetimes of self and a reference in method
(1 answer)
Closed 2 years ago.
I have been working on a simple lexer in rust. However, I have ran into the error[E0502]: cannot borrow 'a_rule' as immutable because it is also borrowed as mutable problem. I have checked other answers and I can't seem to find the reason.
pub struct Rule<'a> {
selector: &'a str,
}
impl<'a> Rule<'a> {
pub fn new(selector: &'a str) -> Self {
Self {
selector
}
}
pub fn get_selector(&'a self) -> &'a str {
self.selector
}
pub fn set_selector(&'a mut self, selector: &'a str) {
self.selector = selector
}
}
#[cfg(test)]
mod tests {
use super::Rule;
#[test]
fn set_selector_test() {
let mut a_rule = Rule::new(".foo");
a_rule.set_selector(".bar");
assert_eq!(a_rule.get_selector(), ".bar")
}
}
Error:
error[E0502]: cannot borrow `a_rule` as immutable because it is also borrowed as mutable
--> src/lib.rs:30:20
|
28 | a_rule.set_selector(".bar");
| ------ mutable borrow occurs here
29 |
30 | assert_eq!(a_rule.get_selector(), ".bar")
| ^^^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here
(Playground)
I would also like to use the opportunity to ask if it is recommended or not to use java like get and set methods or just set the members within a struct as public.
Please feel free to call out any other dumb mistakes.
You’ve tied the lifetime of your rule to the lifetime of your string by making get_selector and set_selector take &'a self/&'a mut self, but that’s not the correct relationship between them. You can produce &'a strs without needing your self to live that long (or be borrowed mutably for that long) because self.selector is already an &'a str.
Remove the 'a on the self references:
pub fn get_selector(&self) -> &'a str {
self.selector
}
pub fn set_selector(&mut self, selector: &'a str) {
self.selector = selector;
}
(but do you need this getter and setter at all? consider immutability!)