Last active
May 3, 2020 23:24
-
-
Save aboglioli/4c0dce8ce7e27126a5b8527cea568a99 to your computer and use it in GitHub Desktop.
Example of self-referenced struct. World struct has multiple players and a property called 'current' referencing one of the players in vector.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::cell::RefCell; | |
use std::rc::Rc; | |
// Using Rc and RefCell | |
#[derive(Debug)] | |
struct Player { | |
name: String, | |
} | |
#[derive(Debug)] | |
struct World { | |
players: Vec<Rc<RefCell<Player>>>, | |
current: Rc<RefCell<Player>>, | |
} | |
impl World { | |
fn set_current_player(&mut self, i: usize) { | |
self.current = Rc::clone(&self.players[i]); | |
} | |
fn set_current_player_name(&self, name: &str) { | |
let mut current = self.current.borrow_mut(); | |
current.name = name.to_string(); | |
} | |
fn print_pointers(&self) { | |
for p in self.players.iter() { | |
println!("{} #pointers: {}", p.borrow().name, Rc::strong_count(p)); | |
} | |
} | |
} | |
// Unsafe pointer | |
#[derive(Debug)] | |
struct UnsafeWorld { | |
players: Vec<Player>, | |
current: Option<*mut Player>, | |
} | |
impl UnsafeWorld { | |
fn set_current_player(&mut self, i: usize) { | |
self.current = Some(&mut self.players[i]); | |
} | |
fn set_current_player_name(&self, name: &str) { | |
if let Some(current_ptr) = self.current { | |
unsafe { | |
(*current_ptr).name = name.to_string(); | |
} | |
} | |
} | |
fn current_player(&self) -> &Player { | |
unsafe { | |
&*self.current.unwrap() | |
} | |
} | |
} | |
fn main() { | |
// SAFE | |
println!("-- SAFE: Rc + RefCell"); | |
let p1 = Rc::new(RefCell::new(Player { | |
name: "Player 1".to_string(), | |
})); | |
let p2 = Rc::new(RefCell::new(Player { | |
name: "Player 2".to_string(), | |
})); | |
let p3 = Rc::new(RefCell::new(Player { | |
name: "Player 3".to_string(), | |
})); | |
let sp2 = Rc::clone(&p2); | |
let mut world = World { | |
players: vec![p1, p2, p3], | |
current: sp2, | |
}; | |
println!("{:#?}", world); | |
world.set_current_player(1); | |
world.set_current_player_name("CHANGE 2"); | |
world.print_pointers(); | |
println!("{:#?}", world); | |
world.set_current_player(2); | |
world.set_current_player_name("CHANGE 3"); | |
world.print_pointers(); | |
println!("{:#?}", world); | |
// UNSAFE | |
println!("-- UNSAFE: ptr"); | |
let p1 = Player { | |
name: "Player 1".to_string(), | |
}; | |
let p2 = Player { | |
name: "Player 2".to_string(), | |
}; | |
let mut world = UnsafeWorld { | |
players: vec![p1, p2], | |
current: None, | |
}; | |
world.set_current_player(1); | |
world.set_current_player_name("CHANGE 2"); | |
println!("{:#?}", world); | |
println!("Current: {:#?}", world.current_player()); | |
let ref_world = &world; | |
ref_world.set_current_player_name("REFERENCE"); | |
println!("{:#?}", ref_world); | |
println!("Current: {:#?}", ref_world.current_player()); | |
move_and_print(world); | |
} | |
fn move_and_print(mut world: UnsafeWorld) { | |
println!("-- PRINT"); | |
//world.set_current_player(0); | |
world.set_current_player_name("SUB-ZERO"); | |
println!("{:#?}", world); | |
println!("Current: {:#?}", world.current_player()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment