rust


How to represent shared mutable state?


I'm trying to learn Rust, but the only thing I do is keep hitting the wall trying to shoehorn familiar (to me) Java concepts into its type system. Or try to shoehorn Haskell concepts, etc.
Let's say I want to write a game, there is a Player and many Resources. Each Resource can be owned by one Player.
struct Player<'a> {
points: i32
}
struct Resource<'a> {
owner: Option<&'a Player<'a>>
}
fn main() {
let mut player = Player{points: 0};
let mut resources = Vec::new();
resources.push(Resource{owner: Some(&player)});
player.points=30;
}
It doesn't compile, because I can't have the resource point to player, while at the same time modifying it. Moreover, if the Resource owned a mutable reference to Player, I couldn't even have two Resources with the same owner.
What is the Rust way to solve such cases?
EDIT:
I oversimplified my question, and while Shepmaster's answer is a correct to it, it's not what I wanted to get (because what I asked was not what I really wanted to ask). I'll try to rephrase it and add more context.
Say the resources are connected in some way - the map of all
resources forms a (un)directed graph.
Each player can own many resources, each resource can be owned by one player. The player should be able to get points from resources he owns. I thought of a signature like: fn addPoints(&mut self, allResources: &ResourcesMap) -> ().
The player can take over a resource connected to one of his resources from another player. It could result in some points loss for the other player.
Problems:
How to represent such graph in Rust (a possibly cyclic structure, where each node can be pointed to from many nodes)?
Here is the original problem. If the Resource points to a Player, I can't modify the player!
Here is the reason for Resource to point to Player - the natural way to do such operation, would be to start from some of Player A's resources, move through the map to a player's B resource and from that resource to player B to subtract the points. It just doesn't seem natural in Rust (at least for me).
The cell documentation page has rather good examples. Rust will always try to protect you from doing bad things (like having two mutable references to the same thing). Therefor it's not quite as "easy" as using Rust's built-in references, since you need to do runtime-checking (Rust references are checked at compile-time).
The RefCell type exists just for that. It checks the mutability rules at runtime. You will get some memory and computation-time overhead, but you end up with the same memory-safety that Rust promises in it's compile-time checks.
Your example ported to RefCell looks like the following.
use std::cell::RefCell;
struct Player {
points: i32
}
struct Resource<'a> { //'
// the lifetime is still needed to guarantee that Resources don't outlive their player
owner: &'a RefCell<Player> //'
}
impl<'a> Resource<'a> {
fn test(&self) -> i32 {
self.owner.borrow().points
}
}
fn main() {
let player = RefCell::new(Player{points: 0});
let mut resources = Vec::new();
resources.push(Resource{owner: &player});
player.borrow_mut().points = 30;
println!("{:?}", resources[0].test());
}
Each Resource can be owned by one Player.
Make the types do that then:
struct Player {
points: i32,
resources: Vec<Resource>,
}
struct Resource {
gold: i32,
}
fn main() {
let player1 = Player{points: 30, resources: vec![Resource { gold: 54 }]};
let player2 = Player{points: 50, resources: vec![Resource { gold: 99 }]};
//If you really need an array of all the resources...
// Although this seems like you should just ask the Player to do something
let mut resources: Vec<_> = vec![];
resources.extend(player1.resources.iter());
resources.extend(player2.resources.iter());
}
Edit Thanks to #ziggystar for pointing out my original version allowed players to only have one Resource. Now players may own N resources, but they still are the only owner of a resource.

Related Links

Borrowing reference in structure
Is only using references the most idiomatic/efficient for “big” structures?
How to write a method that adds `self` as a mutable trait reference to a collection?
How do I modify a value after matching on it?
Drop a Rust void pointer stored in an FFI
Iterate two vectors and the rest of the larger one
How do I implement Clone/Copy for an enum that contains a String?
Modeling embedded hardware in Rust and how to have multiple mutable references cleanly?
Should I borrow or copy my small data types?
Using pointer casting to change the “type” of data in memory [duplicate]
Export function only to module test?
Take slice of certain length known at compile time
Is it possible to deactivate file locking in cargo?
“does not live long enough” error in same function
What ways exist to create containers of several types? [duplicate]
How can I optimize reading a UTF-8 string from a file with a known offset and size?

Categories

HOME
verification
freeradius
apple-push-notifications
clearcase
barcode-scanner
couchdb
operating-system
dafny
hdfs
bing-search
fogbugz
amp
material-components
tweepy
eddystone
twitter-oauth
fireloop
phpstorm-2017.1
android-externalstorage
fullcalendar-scheduler
pinterest
user-defined-types
gmp
nose
bluemix-mobile-services
gitkraken
android-permissions
dashdb
uislider
device
substring
tracing
clipboard
openbravo
acrobat
sfml
mdns
credit-card
tilemill
tightvnc
grails-2.5
spinner
code-rally
uivisualeffectview
cloudera-quickstart-vm
reset
moinmoin
zend-form
gcal
roracle
head.js
lightning-workbench
renderman
winston
solr-query-syntax
punctuation
gtk#
gnome-terminal
dymola
front-camera
libharu
e
oci
static-methods
vaadin4spring
xcopy
verisign
wif4.5
ui4j
linuxbrew
opencyc
extend
apple
uitest
embeddedwebserver
ocmockito
scala-swing
android-audiomanager
ssmtp
htmltidy
n-tier-architecture
inequality
distributed-r
neo4jphp
hyperloglog
usb-flash-drive
node.js-stream
web-frameworks
jsplitpane
story
android-dialog
first-class
exponent
gaelyk
ccnet-config
spring-modules
autobench
jboss-mdb
suggestbox
html-generation
error-detection

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App