Workaround needing multiple mutable references - rust

I am trying to implement a cli blackjack game in Rust. At the end of each round I want to calculate the winning player and move the cards in each player (including the winner)'s hand into the winners won_hand field.
The project structure has a Table struct which holds players and a deck (Vec<Card>). A Player has a hand field containing their current cards, won_cards which contains all the cards they have won in the game , status, etc.
The logic to calculate the winner is a method on Table. It returns a mutable reference because I want to append to the winner's won_cards field:
/// The current winning player at the table, or None if all players are bust.
pub fn winner(&mut self) -> Option<&mut Player> {
self.players
.iter_mut()
.filter(|p| p.stat != PlayerStat::Bust)
.max_by(|p1, p2| p1.hand_worth().cmp(&p2.hand_worth()))
}
there is also a helper method to collect the cards out of all the players' hands:
pub fn collect_cards(&mut self) -> Vec<Card> {
let mut cards = vec![];
for player in self.players.iter_mut() {
cards.append(&mut player.hand);
}
cards
}
So I could collect the cards and then calculate the winner, which is what I have right now:
let mut drawn_cards = table.collect_cards();
let winner = match table.winner() {
Some(w) => w,
None => {
println!("All players are bust!");
println!("All cards will be reshuffled into the deck.");
table.deck.append(&mut drawn_cards);
table.deck.shuffle(&mut thread_rng());
wait_for_enter();
continue;
}
};
println!("The winner is... {}!", winner.name);
winner.won_cards.append(&mut drawn_cards);
But the problem with that is when I call winner() all the player's hands have already been emptied by collect_cards, meaning the result will be wrong.
I can't call winner before collect_cards because then to use the mutable reference to append the drawn cards to the winner's hand I'd have multiple mutable references at once.
I'm stuck as to how to work around this, is it even possible to do cleanly or would I have to do some restructuring first?

Related

How to atomically access multiple things that might be held by the same lock(s)?

I have a big grid which multiple threads access simultaneously. I have it divided into regions, each of which is independently locked. I want to be able to have atomic operations that operate on specified sets of points, which may or may not be part of the same region.
What I have now includes:
pub struct RwGrid<T>{
width : usize,
height : usize,
region_size : usize,
regions : [RwLock<Vec<T>>; TOTAL_REGIONS]
}
impl<T: Copy + Colored> Grid<T> for RwGrid<T>{
...
fn set_if<F>(&self, p : Point, f : F, value : T) -> bool where
F : Fn(T) -> bool{
let (region_index, index_in_region) = self.map_coordinates(p);
let mut region = self.regions[region_index].write().unwrap();
let pre_existing = region[index_in_region];
if f(pre_existing){
region[index_in_region] = value;
true
} else {false}
}
...
}
Where map_coordinates is a helper function that maps Cartesian coordinates onto the index of the appropriate region, and the index of the given point within that region.
My goal is (among other things) a variant of that set_if function that atomically looks at a set of points, rather than a single point (specifically, it would look at the nine points making up the immediate neighborhood of a given point.) This set of points might be from the same region, or might come from multiple regions. Further, the locks need to be acquired in a particular order, or deadlock may be possible.
The atomicity requirement is important to note. If it helps, imagine you're trying to sometimes color points red, with the invariant that no red point may be adjacent to another red point. If two threads non-atomically read the neighborhood of the point they're considering, they may interleave, both checking that the other's target point is currently black, then setting two adjacent points red.
I don't know how to abstract over this. I can easily find the regions for a set of points, or for a single point I can acquire the lock and operate on it, but I've been beating my head on how to acquire a set of locks and then operate on points using the appropriate lock, without having enormous amounts of hard-coded boiler plate.
To illustrate the problem, here's a variant of set_if that looks at just two points, and sets one of them based on a condition that depends on both:
fn set_if_2<F>(&self, p1 : Point, p2 : Point, f : F, value : T) -> bool where
F : Fn(T, T) -> bool{
let (region_index_1, index_in_region_1) = self.map_coordinates(p1);
let (region_index_2, index_in_region_2) = self.map_coordinates(p2);
if (region_index_1 == region_index_2){
let mut region = self.regions[region_index_1].write().unwrap();
let pre_existing_1 = region[index_in_region_1];
let pre_existing_2 = region[index_in_region_2];
if f(pre_existing_1, pre_existing_2){
region[index_in_region_1] = value;
true
} else {false}
} else {
let mut region1 = self.regions[region_index_1].write().unwrap();
let region2 = self.regions[region_index_2].write().unwrap();
let pre_existing_1 = region1[index_in_region_1];
let pre_existing_2 = region2[index_in_region_2];
if f(pre_existing_1, pre_existing_2){
region1[index_in_region_1] = value;
true
} else {false}
}
}
This code has two branches based on whether or not the points belong to the same region (and thus need one lock) or different regions (each with their own lock.) As you can imagine, expanding that pattern out to nine different points that might belong to many different configurations of region would be painful and wrong.
So far I have two ideas and they both sound bad:
Have a function that returns a Vec<RwLockWriteGuard<T>> and a structure which holds indexes into that vector each point should use. (So if all points come from the same region, the Vec would be one element long and each point would map to 0).
Have the data actually live in a single unsafe Vec with no locks (I'm not even sure how to do that), but have "fake" locks corresponding to regions, and code the Region module so that points are only accessed after the corresponding lock has been grabbed. One chunk of code could then recognize and acquire the appropriate locks, but that would be independent of subsequently reading or writing to the points.
Are either of those ideas workable? Is there a better way to approach this?
EDIT: Some more code:
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Point(pub usize, pub usize);
fn map_coordinates(&self, p : Point) -> (usize, usize){
let Point(x, y) = self.fix(p);
let (region_width, region_height) = (self.width / REGIONS_PER_DIMENSION, self.height/REGIONS_PER_DIMENSION);
let (target_square_x, target_square_y) = (x/region_width, y/region_height);
let target_square_i = target_square_y * REGIONS_PER_DIMENSION + target_square_x;
let (x_in_square, y_in_square) = (x % region_width, y % region_width);
let index_in_square = y_in_square * region_width + x_in_square;
(target_square_i, index_in_square)
}
fn fix(&self, p: Point) -> Point{
let Point(x, y) = p;
Point(modulo(x as i32, self.width), modulo(y as i32, self.height))
}
#[inline(always)]
pub fn modulo(a: i32, b: usize) -> usize {
(((a % b as i32) + b as i32) % b as i32) as usize
}
One thing to note is that the wrapping behavior (which is enabled by the fix function above) slightly complicates avoiding deadlocks. Points will often be accessed by compass direction, like asking for the northern neighbor of a point. Because the grid wraps, if you always lock in order by compass direction - like, "Northern neighbor, then center, then southern" - you can get a deadlocked cycle. Another way of phrasing this is that if you access Points by the order they're specified in the request, rather than by the order they exist in the grid, you can get cycles.
Alright, so I've figured out a couple ways to do this. Both have the same signature of taking a generic number of points, and treating the point at index 0 as the "target" point to write the value to.
Without Allocating
This version loops through all points for each region at play, making it O(R*P) where R is the number of regions and P is the number of points.
fn set_if<const N: usize, F: Fn([T; N]) -> bool>(&self, points: [Point; N], f: F, value: T) -> bool {
// The region and index within that region for each point
let point_coords = points.map(|p| self.map_coordinates(p));
// Extract the target point data for direct usage later
let (target_region_index, target_index_in_region) = point_coords[0];
// Iterate through the regions, locking each one,
// and reading the pre-existing values.
let mut pre_existing = [None; N];
// Loop through each region
let mut region_locks: [_; TOTAL_REGIONS] = std::array::from_fn(|region_index| {
let mut region = None;
// Loop through each point
for (j, (this_region_index, index_in_region)) in point_coords.into_iter().enumerate() {
// If the point is in this region
if this_region_index == region_index {
// Acquire a new lock if necessary
// (if this is the first point in the region)
let region = region.get_or_insert_with(|| {
self.regions[region_index].write().unwrap()
});
// Then read the pre-existing value for this point
pre_existing[j] = Some(region[index_in_region])
}
}
// Store region locks to hold the lock until we're done
region
});
// Should never fail
let pre_existing = pre_existing.map(|v| v.unwrap());
let target_region = region_locks[target_region_index].as_mut().unwrap();
if f(pre_existing) {
target_region[target_index_in_region] = value;
true
} else {
false
}
// Region locks dropped at end of scope
}
With Allocating
This version loops through all points once, collecting the points for each region, and then loops through each region with points, obtaining a lock and handling each point in the region.
This makes it O(R+2P).
fn set_if<const N: usize, F: Fn([T; N]) -> bool>(&self, points: [Point; N], f: F, value: T) -> bool {
// Store a set of indices for each region
let mut region_indices: [Vec<(usize, usize)>; TOTAL_REGIONS] = Default::default();
// Handle the target point first
let (target_region_index, target_index_in_region) = self.map_coordinates(points[0]);
region_indices[target_region_index] = vec![
// We store the index of the point in `points` and
// the index associated with that point within its region
(0, target_index_in_region),
];
// Then handle all of the rest
for (j, p) in points.into_iter().enumerate().skip(1) {
let (region_index, index_in_region) = self.map_coordinates(p);
// Store the index of the point within `points` and
// the index associated with that point within its region
region_indices[region_index].push((j, index_in_region));
}
// Iterate through the regions, locking each one,
// and reading the pre-existing values.
let mut pre_existing = [None; N];
// Store region locks to hold the lock until we're done
let mut region_locks: [_; TOTAL_REGIONS] = Default::default();
for (region_index, indices_in_region) in region_indices.into_iter().enumerate() {
// Skip if there were no points in this region
if indices_in_region.is_empty() {
continue;
};
// Acquire a lock for this region
let region = self.regions[region_index].write().unwrap();
// Read the pre-existing value for each point in the region
for (j, index_in_region) in indices_in_region {
pre_existing[j] = Some(region[index_in_region]);
}
// Store region locks to hold the lock until we're done
region_locks[region_index] = Some(region);
}
// Should never fail
let pre_existing = pre_existing.map(|v| v.unwrap());
let target_region = region_locks[target_region_index].as_mut().unwrap();
if f(pre_existing) {
target_region[target_index_in_region] = value;
true
} else {
false
}
// Region locks dropped at end of scope
}
I prefer option #1, because it is simpler and has no allocations. Given you will likely have a small fixed number of regions and points, I expect performance of option 1 to be better as well. If performance is very important, I'd recommend benchmarking both, though.

How to rotate a linked list in Rust?

I came across a leetcode example https://leetcode.com/problems/rotate-list/ and wanted to implement it in Rust but I keep moving out of my variables. For instance if I use head to track down the end of the list I cannot move its value to the last next because it is already moved out of the variable. How should I think to avoid this kind of problems?
And this is my attempt in rust
// Definition for singly-linked list.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ListNode {
pub val: i32,
pub next: Option<Box<ListNode>>,
}
impl ListNode {
#[inline]
fn new(val: i32) -> Self {
ListNode { next: None, val }
}
}
pub fn rotate_right(head: Option<Box<ListNode>>, k: i32) -> Option<Box<ListNode>> {
if k == 0 {
return head;
}
let mut len = 0;
let mut curr = &head;
while let Some(n) = curr {
curr = &n.next;
len += 1;
}
drop(curr);
let newk = len - ( k % len);
println!("Rotate {} right is {} mod {}",k,newk,len);
let mut node = head.as_ref();
for _i in 0..newk {
if let Some(n) = node {
node = n.next.as_ref();
}else {
println!("Unexpected asswer fail");
}
}
let mut newhead = None ;// node.unwrap().next; // node will be last and newhead will be first.
if let Some(mut n) = node{ // node should have a value here
newhead = n.next;
n.next = None
}
drop(node);
let node = newhead;
if let Some(c) = node{
let mut curr = c;
while let Some(next) = curr.next {
curr = next;
}
curr.next = head;
newhead
}else{
println! ("Todo handle this corner case");
None
}
}
But this yields errors about moving and use of borrowed references.
error[E0507]: cannot move out of `n.next` which is behind a shared reference
--> src/main.rs:99:23
|
99 | newhead = n.next;
| ^^^^^^
| |
| move occurs because `n.next` has type `Option<Box<ListNode>>`, which does not implement the `Copy` trait
| help: consider borrowing the `Option`'s content: `n.next.as_ref()`
error[E0594]: cannot assign to `n.next` which is behind a `&` reference
--> src/main.rs:100:13
|
98 | if let Some(mut n) = node{ // node should have a value here
| ----- help: consider changing this to be a mutable reference: `&mut Box<ListNode>`
99 | newhead = n.next;
100 | n.next = None
| ^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written
error[E0382]: use of moved value: `newhead`
--> src/main.rs:111:13
|
97 | let mut newhead = None ;// node.unwrap().next; // node will be last and newhead will be first.
| ----------- move occurs because `newhead` has type `Option<Box<ListNode>>`, which does not implement the `Copy` trait
...
104 | let node = newhead;
| ------- value moved here
...
111 | newhead
| ^^^^^^^ value used here after move
Finlay this is reference code in c of what I intended it to look like:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* rotateRight(struct ListNode* head, int k){
struct ListNode* node = head;
int len = 1;
if (k == 0 || !head){
return head;
}
while (node->next){
node = node->next;
len++;
}
int newk = len - (k % len) -1;
node = head;
while (newk--){
if (node->next) {
node = node->next;
}
}
if ( !node->next) {
return head; // do not move anything
}
struct ListNode* newhead = node->next; // node will be last and newhead will be first.
struct ListNode* n = node->next;
node->next = 0;
node = n;
while (node->next != 0) {
node = node->next;
}
node->next = head;
return newhead;
}
So my question is what technique can be used to avoid this move use trap?
I'd like to preface this post by saying that this type of Linked List in Rust is not a particularly good representation. Unfortunately, safe Rust's ownership model makes reference chain structures such as Linked Lists problematic and hard to reason about for any more than simple operations, despite Linked Lists being very simple in other languages. While for beginners, simple but inefficient implementations of simple concepts are often important and useful, I would also like to emphasize that the safe Rust "sentinel model" for trees and linked lists also has a heavy performance cost. Learning Rust With Entirely Too Many Linked Lists is the de facto book for learning how to properly deal with these structures, and I recommend it to all beginners and intermediate Rust programmers who haven't worked through it (or at least skimmed it).
However, this particular operation is possible on sentinel model singly linked lists in purely safe Rust. The whole version of the code I'm about to present is available on the Playground, which includes some things like test cases and an iterator implementation I'll be glossing over (since it doesn't get to the core of the problem and is only used in test cases and to derive the entire size of the Linked List). I also won't be presenting the ListNode struct or the new function, since they are in the question itself. Note that I also took some design liberties (instead of a free function, I made rotate_right and rotate_left member functions, you can freely convert but this is more Rusty design).
The "obvious' implementation here is to drain the entire list and reconstruct it. This is a perfectly good solution! However it's likely inefficient (it can be more or less inefficient depending on whether you totally destroy the nodes or not). Instead we're going to be doing what you largely do in other languages: only breaking the link and then reassigning the pointers at the boundaries. In fact, once you break it down into these two steps, the problem becomes much easier! All that's required is knowledge about Rust's mutable borrowing semantics, and how to overcome the pesky requirement that references always have a definite value and cannot be moved out of.
1. Breaking the Link: mutable reference uniqueness & memory integrity
/// Splits the list at a given index, returning the new split off tail.
/// Self remains unmodified.
/// The list is zero indexed, so,
/// for instance, a value of 2 in the list [1,2,3,4,5]
/// will cause self to be [1,2,3] and the return value to be
/// Some([4,5]). I.E. the link is "broken" AT index 2.
///
/// If there's nothing to split off, `None` is returned.
fn split_at(&mut self, n: usize) -> Option<Self> {
use std::mem;
let mut split = Some(self);
for _ in 0..n {
if let Some(node) = split.map(|v| v.next.as_deref_mut()) {
split = node;
} else {
return None;
}
}
match split {
Some(node) => {
let mut new_head = None;
mem::swap(&mut new_head, &mut node.next);
new_head.map(|v| *v)
}
None => None
}
}
The logic is straightforward (if you've broken off a list in any other language it's the exact same algorithm). The important thing for Rust is the ownership system and the mem::swap function. Rust ensures two things that are problematic here:
You're not mutably borrowing the same thing twice.
No piece of memory is invalid, even temporarily (particularly in self).
For 1., we use the code
if let Some(node) = split.map(|v| v.next.as_deref_mut()) {
split = node;
}
What this does is simply advances the pointer, making sure to immediately "forget" our current mutable pointer, and never do anything that directly causes "self" to be used at the same time as "node". (Note that if you tried this in an earlier version of Rust, I don't believe this was possible before Non-Lexical Lifetimes (NLLs), I think it would both alias self and node under the old rules). The map is simply to allow us to reassign to split by "reborrowing" the inner Box as an actual reference, so we can recycle the seed variable we start as self (since you can't reassign self in this way).
For solving 2. we use:
match split {
Some(node) => {
let mut new_head = None;
mem::swap(&mut new_head, &mut node.next);
new_head.map(|v| *v)
}
None => None
}
The key here is the mem::swap line. Without this Rust will complain about you moving node.next. Safe Rust requires you to ensure there is always a value in every variable. The only exception is if you're permanently destroying a value, which doesn't work on references. I think there's some QOL work on the compiler at the moment to allow you to move out of a mutable reference if you immediately put something in its place and the compiler can prove there will be no panic or return between these operations (i.e. memory cannot become corrupted during a stack unwind), but as of Rust 1.47 this is not available.
2. Stitching the list back together: memory integrity
/// Attaches the linked list `new_tail` to the end
/// of `self`. For instance
/// `[1,2,3]` and `[4,5]` will make self a list containing
/// `[1,2,3,4,5]`.
fn extend_from_list(&mut self, new_tail: ListNode) {
let mut tail = self;
while tail.next.is_some() {
tail = tail.next.as_deref_mut().unwrap();
}
tail.next = Some(Box::new(new_tail))
}
This method isn't too complicated, it just assigns the next reference to the head node of the passed in list. If you've written a function to attach a new node it's functionally the same. Again, the key is that we advance the pointer to the end, being very careful we never allow a mutable reference to alias, which allows us to appease the Borrow Checker.
From there, we can finish up!
/// Rotates the list `k` elements left. So
/// `[1,2,3]` rotated 2 left is `[3,1,2]`.
///
/// The function handles rotating an arbitrary number of steps
/// (i.e. rotating a size 3 list by 5 is the same as rotating by 2).
fn rotate_left(&mut self, k: usize) {
use std::mem;
let k = k % self.iter().count();
if k == 0 {
return;
}
let k = k-1;
if let Some(mut new_head) = self.split_at(k) {
mem::swap(self, &mut new_head);
let new_tail = new_head;
self.extend_from_list(new_tail);
} else {
unreachable!("We should handle this with the mod!")
}
}
/// Rotates the list `k` elements right. So
/// `[1,2,3]` rotated 2 right is `[2,3,1]`.
///
/// The function handles rotating an arbitrary number of steps
/// (i.e. rotating a size 3 list by 5 is the same as rotating by 2).
fn rotate_right(&mut self, k: usize) {
self.rotate_left(self.iter().count() - k)
}
Rotating left is conceptually easiest, since it's just splitting a list at the given index (k-1 because to rotate k places we need to break the link after counting one fewer indices). Again, we need to make use of mem::swap, the only tricky thing about this code, because the part we split off is the new head and Rust won't let us use temp variables due to the memory integrity guarantee.
Also, it turns out rotating right k places is just rotating left size-k places, and is much easier to conceptualize that way.
This is all somewhat inefficient though because we're marching to the end of the list each time (particularly for the list fusion), because we're not holding onto the tail pointer and instead re-iterating. I'm fairly certain you can fix this, but it may be easier to make it one large function instead of sub-functions, since returning a downstream tail pointer would require some lifetime flagging. I think if you want to take a next step (besides the Linked List book, which is probably a better use of your time), it would be good to see if you can preserve the tail pointer to eliminate the constant marching down the list.

Alternative to passing a vector to a function?

I'm currently learning rust by writing a project which is a clone of the board game "Puerto Rico".
the Game struct:
I chose the players member to be an array slice because it can only contain 3, 4 or 5 players (to my understanding, this is the perfect use case for an array slice inside a struct, instead of a Vec)
the Game::new function:
Returns a new Game instance. It takes a list of the names of the players and an empty Vec and populates it with the appropriate Player instances then stores it in the Game as an array slice.
The problem is that this method of instantiating the Game struct seems kind of cumbersome and I feel like there is a way around it (as in passing only the names parameter and somehow creating the array slice inside the new function).
So, is there a way to do it? Should I just change the players member to a Vec?
I tried to move the vec!() declaration inside the new function but, of course, it doesn't work becuase it is dropped at the end of the block.
use super::board::Board;
use super::player::Player;
use super::planatation::ResourceType;
#[derive(Debug)]
pub struct Game<'a> {
board: Board,
players: &'a [Player],
governor: &'a Player
}
impl<'a> Game<'a> {
pub fn new(names: &[String], players: &'a mut Vec<Player>) -> Self {
let num_of_players = names.len() as i32;
let board = Board::new(num_of_players);
if num_of_players < 3 || num_of_players > 5 {
panic!("Only 3, 4 or 5 players may play");
}
if num_of_players < 5 {
for (i, name) in names.iter().enumerate() {
if i < 2 {
players.push(Player::new(name.to_string(), ResourceType::Indigo));
} else {
players.push(Player::new(name.to_string(), ResourceType::Corn));
}
}
} else { // num_of_player == 5
for (i, name) in names.iter().enumerate() {
if i < 3 {
players.push(Player::new(name.to_string(), ResourceType::Indigo));
} else {
players.push(Player::new(name.to_string(), ResourceType::Corn));
}
}
}
Game {
board: board,
players: players,
governor: &players[0]
}
}
}
As you already noticed, a slice does not own its data, it only references them. This is why you must create the players outside of the struct and pass them to the game struct. If you want your struct to hold the players, they must be a Vec instead of a slice.
If governor was not a member of the struct, I would suggest simply using a Vec (or ArrayVec) and be done with it. This, however would mean that governor cannot (generally) be a reference to this very same vector (see Why can't I store a value and a reference to that value in the same struct?).
Depending on the exact semantics and use cases of governor and the other, "regular" players, I would do one of the following:
Having a Vec (or ArrayVec) for "regular" players, and an extra field for the governor. This may be cumbersome if you often have to do the same for both "regular" players and the governor, but you could introduce a method that returns an iterator over all the players and the governor.
Having a Vec (or ArrayVec) for all players, and just store the index into the vector for the governor. As a variation, you could enforce that the governor is always the first element of the Vec holding all players.
Doing as you already did. (This, however, will possibly mean that you cannot easily mutate them (because you can only have one mutable reference at a time). You may work around this via interior mutability, but I am not sure if it is worth it)
Only store a Vec<String> holding the player names. From that, you could derive the number of players. If the kind of player is reasonably simple, you may get away with not even storing the players explicitly, but derive the kind of player by its index (which I suppose may be possible because of the way you determine Indigo or Corn). The disadvantage is that you do not have a player around, but maybe you can model the entire game without them.

Boxed value does not live long enough

I'm trying to implement a cons list in Rust as an exercise. I've managed to solve all of my compiler errors except this one:
Compiling list v0.0.1 (file:///home/nate/git/rust/list)
/home/nate/git/rust/list/src/main.rs:18:24: 18:60 error: borrowed value does not live long enough
/home/nate/git/rust/list/src/main.rs:18 List::End => list = &*(box List::Node(x, box List::End)),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/nate/git/rust/list/src/main.rs:16:34: 21:2 note: reference must be valid for the anonymous lifetime #1 defined on the block at 16:33...
/home/nate/git/rust/list/src/main.rs:16 fn add(mut list: &List, x: uint) {
/home/nate/git/rust/list/src/main.rs:17 match *list {
/home/nate/git/rust/list/src/main.rs:18 List::End => list = &*(box List::Node(x, box List::End)),
/home/nate/git/rust/list/src/main.rs:19 List::Node(_, ref next_node) => add(&**next_node, x),
/home/nate/git/rust/list/src/main.rs:20 }
/home/nate/git/rust/list/src/main.rs:21 }
/home/nate/git/rust/list/src/main.rs:18:16: 18:60 note: ...but borrowed value is only valid for the expression at 18:15
/home/nate/git/rust/list/src/main.rs:18 List::End => list = &*(box List::Node(x, box List::End)),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
Could not compile `list`.
To learn more, run the command again with --verbose.
And the code that I'm trying to compile:
enum List {
Node(uint, Box<List>),
End,
}
fn main() {
let mut list = new();
add(&*list, 10);
//add(list, 20);
//add(list, 30);
print(&*list);
}
fn add(mut list: &List, x: uint) {
match *list {
List::End => list = &*(box List::Node(x, box List::End)),
List::Node(_, ref next_node) => add(&**next_node, x),
}
}
fn new() -> Box<List> {
box List::End
}
So why don't the boxed values live long enough? Is it because I immediately dereference them? I tried it this way:
match *list {
List::End => {
let end = box List::Node(x, box List::End);
list = &*end;
}
List::Node(_, ref next_node) => add(&**next_node, x),
}
But I got exactly the same error. What am I missing?
I think you’re missing some key details of Rust; there are three things that I think we need to deal with:
How patterns work;
The distinction between immutable (&) and mutable (&mut) references;
How Rust’s ownership model works (because of your &*box attempts).
I’ll deal with the patterns part first; in fn add(mut list: &List, x: uint), there are two patterns being used, mut list and x. Other examples of patterns are the left hand side of let lhs = rhs; and the bit before the => on each branch of a match expression. How are these patterns applied to calls, effectively? It’s really like you’re doing this:
fn add(__arg_0: &List, __arg_1: uint) {
let mut list = __arg_0;
let x = __arg_1;
…
}
Perhaps that way of looking at things will make it clearer; the signature of a function does not take the patterns that the variables are bound to into account at all. Your function signature is actually in canonical form fn add(&List, uint). The mut list part just means that you are binding the &List value to a mutable name; that is, you can assign a new value to the list name, but it has no effect outside the function, it’s purely a matter of the binding of a variable to a location.
Now onto the second issue: learn the distinction between immutable references (type &T, value &x) and mutable references (type &mut T, value &x). These are so fundamental that I won’t go into much detail here—they’re documented sufficiently elsewhere and you should probably read those things. Suffice it to say: if you wish to mutate something, you need &mut, not &, so your add method needs to take &mut List.
The third issue, that of ownership: in Rust, each object is owned in precisely one location; there is no garbage collection or anything, and this uniqueness of ownership means that as soon as an object passes out of scope it is destroyed. In this case, the offending expression is &*(box List::Node(x, box List::End)). You have boxed a value, but you haven’t actually stored it anywhere: you have just tried to take a reference to the value contained inside it, but the box will be immediately dropped. What you actually want in this case is to modify the contents of the List; you want to write *list = List::Node(x, box List::End), meaning “store a List::Node value inside the contents of list” instead of list = &…, meaning “assign to the variable list a new reference”.
You’ve also gone a tad overboard with the boxing of values; I’d tend to say that new() should return a List, not a Box<List>, though the question is slightly open to debate. Anyway, here’s the add method that I end up with:
fn add(list: &mut List, x: uint) {
match *list {
List::End => *list = List::Node(x, box List::End),
List::Node(_, box ref mut next_node) => add(next_node, x),
}
}
The main bit you may have difficulty with there is the pattern box ref mut next_node. The box ref mut part reads “take the value out of its box, then create a mutable reference to that value”; hence, given a Box<List>, it produces a &mut List referring to the contents of that box. Remember that patterns are completely back to front compared with normal expressions.
Finally, I would strongly recommend using impls for all of this, putting all the methods on the List type:
enum List {
Node(uint, Box<List>),
End,
}
impl List {
fn new() -> List {
List::End
}
fn add(&mut self, x: uint) {
match *self {
List::End => *self = List::Node(x, box List::End),
List::Node(_, box ref mut next_node) => next_node.add(x),
}
}
}
fn main() {
let mut list = List::new();
list.add(10);
}
Your attempts to fix the other compiler errors have, unfortunately, led you to a dark place of inconsistency. First you need to make up your mind whether you want a Box<List> or a List as your handle for the head of a (sub-)list. Let's go with List because that is more flexible and generally the path of least resistance.
Then, you need to realize there is a difference between mut list: &List and list: &mut List. The first is a read-only reference which you can change to point at other read-only things. The second is a read-write reference which you can not change to point at other read-write things. There's also mut list: &mut List because these two capabilities are orthogonal.
In add, when you write list = ..., you are only affecting your local variable. It has no effect on the caller. You want to change the list node the caller sees! Since we said we wanted to deal with List, not boxes, we'll change the contents of the list nodes that exist (replacing the final End with a Node(..., box End)). That is, signature and code change as follows:
fn add(list: &mut List, x: uint) {
match *list {
List::End => *list = List::Node(x, box List::End),
List::Node(_, box ref mut next_node) => add(next_node, x),
}
}
Note that *list = is different from list =, in that we now change the contents of the list node in-place instead of making our local reference point at a different node.
For consistency and ergonomics (and a tiny bit of efficiency), you should probably change new to return a bare List, i.e.:
fn new() -> List {
List::End
}
This also saves you all the nasty reborrowing (&*) in the calls:
let list = new(); // type: List
add(&mut list, 10);
Finally, as for why the box did not live long enough: Well, you basically created a local/temporary box, took a reference to it, and then attempted to pass on the reference without keeping the box alive. A box without an owner is deallocated, so you need to give it an owner. In the fixed code above, the owner is the next field of the List::Node we create and write to the &mut List.

How to reference multiple members in an array?

I have an array of two players. I have a variable, current_num which is equal to which player in the array is the current player. I have a while loop which iterates through the main game logic where sometimes current_num is updated, sometimes it stays the same. I would like to assigned a current_player and next_player variable each iteration of the loop as like so:
while !self.board.check_win() {
let ref mut current_player = self.players[current_num];
let ref mut next_player = self.players[(current_num+1)%2];
/* Game Logic */
}
This doesn't work because I try to borrow something from self.players[..] twice. I honestly don't even need the next_player variable if I could somehow store the next player inside the first player object, but you can't create cyclic data structures in rust it seems. I fought so hard with the compiler to accomplish the following:
player1.next = &player2;
player2.next = &player1;
Unfortunately that doesn't seem to be possible.... If it is, I would rather do that so that I could do something along the lines of:
current_player.next().do_something();
instead of needing a next_player variable. I would also be able to do:
current_player = current_player.next();
for switching to the next player so I wouldn't even have to keep an index variable (current_num).
Now I do have a working mode where I always refer to the current player as:
self.players[current_num].do_something() //current_player
self.players[(current_num+1)%2).do_something() //next_player
This avoids the borrowing issues, but makes for VERY verbose code that's hard to read. C/C++ are really much easier with regards to getting this kind of design working. I feel like I'm constantly fighting the compiler to get what I want done...
Any help would be greatly appreciated!
To solve your immediate problem you can use the mut_split_at method, this uses unsafe code internally to give you two disjoint slices into a vector, resolving all your borrowing issues. You might write a wrapper like:
fn double_index<'a, T>(x: &'a mut [T],
i: uint, j: uint) -> (&'a mut T, &'a mut T) {
assert!(i != j, "cannot double_index with equal indices");
if i < j {
let (low, hi) = x.mut_split_at(j);
(&mut low[i], &mut hi[0])
} else { // i > j
let (low, hi) = x.mut_split_at(i);
(&mut hi[0], &mut low[j])
}
}
then write
let (current_player, next_player) = double_index(self.players,
current_num,
(current_num + 1) % 2);
(Assuming self.players is a [Player, .. 2] or &mut [Player]. If it is a Vec<Player> you will need to call .as_mut_slice() explicitly.)
you can't create cyclic data structures in rust it seems
You can, using Rc and Weak. For shared mutability, you'll need to use RefCell or Cell. E.g.
use std::rc::{Rc, Weak};
use std::cell::RefCell;
struct Player {
// ...
next: Option<Weak<RefCell<Player>>>
}
impl Player {
fn next(&self) -> Rc<RefCell<Player>> {
// upgrade goes from Weak to Rc & fails if this is invalid
self.next.unwrap().upgrade()
}
}
let player1 = Rc::new(RefCell::new(Player { ..., next: None }));
let player2 = Rc::new(RefCell::new(Player { ..., next: None }));
// join them up; downgrade goes from Rc to Weak
player1.borrow_mut().next = Some(player2.downgrade());
player2.borrow_mut().next = Some(player1.downgrade());
This avoids the borrowing issues, but makes for VERY verbose code that's hard to read. C/C++ are really much easier with regards to getting this kind of design working. I feel like I'm constantly fighting the compiler to get what I want done...
Any sort of shared mutability is very easy to get wrong; and in languages without a GC, this can lead to dangling pointers, segfaults & security holes. Unfortunately sealing all the holes in the manner that Rust does leads to this type of thing being rather ugly at times.
Alternatively:
use std::cell::RefCell;
struct Player;
fn main() {
let players = Vec::from_fn(3, |_| RefCell::new(Player));
let mut player_1 = players.get(0).borrow_mut();
let mut player_2 = players.get(1).borrow_mut();
//Happily mutate both players from here on
}
Normally mutating an object which has been borrowed multiple times isn't allowed. You can't have multiple &mut references to the same object, but multiple & references are allowed because they don't allow mutation. Since Cell and RefCell have internal mutability, we can borrow them via & reference while still mutating their contents.

Resources