Cannot move out of shared reference of a recursive struct - rust

I am trying to implement Gale-Shapley algorithm in Rust and I need to declare a recursive struct like this:
#[derive(Eq, PartialEq, PartialOrd)]
struct Person {
name: char,
preference: Vec<Person>,
pref_index: usize,
candidates: Vec<Person>,
partner: Option<Box<Person>>, // using Box makes it easier to declare recursive structs
}
impl Person {
fn propose_to_next(&mut self) {
/* propose to next most preferred person */
if self.pref_index >= self.preference.len() {
()
}
let person = self.preference[self.pref_index];
self.candidates.push(person);
self.pref_index += 1;
}
fn pick_preferred(&mut self) {
/* pick the next more preferred partner or stay with the current one */
for person in &self.preference {
let p = Some(Box::new(*person));
if p == self.partner {
break;
} else if self.candidates.contains(&person) {
self.partner = p;
break;
}
}
}
}
But this gives me the error
error[E0507]: cannot move out of index of `std::vec::Vec<Person>`
--> src/lib.rs:18:22
|
18 | let person = self.preference[self.pref_index];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| move occurs because value has type `Person`, which does not implement the `Copy` trait
| help: consider borrowing here: `&self.preference[self.pref_index]`
error[E0507]: cannot move out of `*person` which is behind a shared reference
--> src/lib.rs:29:35
|
29 | let p = Some(Box::new(*person));
| ^^^^^^^ move occurs because `*person` has type `Person`, which does not implement the `Copy` trait
How do I fix this? Is my approach flawed? I tried a non OO approach using just vectors and hashmaps but it is ugly since I will have to pass in everything in every function.

This should probably do it in your case.
Notice how the struct doesn't have ownership of either the elements of the preference vector or the partner but just holds a (static for simplicitly) reference to them.
Notice also that you have to implement the PartialEq trait for this to work
use std::vec::Vec;
struct Person {
name: char,
preference: Vec<&'static Person>,
partner: Option<&'static Person>
}
impl Person {
fn pick_preferred(&mut self, candidates: &Vec<Person>) {
for person in &self.preference {
if candidates.contains(&person) {
self.partner = Some(person);
}
}
}
}
impl PartialEq for Person {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
pub fn main() {
let candidates: Vec<Person>;
let p: Person;
....
}
Playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=4b1fab2d4f2188c8d50fd21762ad126c

Related

Pass self as mutable reference while iterating over collection [duplicate]

This question already has answers here:
Modifying one attribute of a struct while iterating over another attribute
(4 answers)
Closed last month.
I want to iterate over a vector (or map) of actors in a world struct. The actors need access to the world as they might need to get information about the world, but can also change the state of the world. I should this be done properly in rust?
struct Actor {
}
impl Actor {
pub fn step(&mut self, world: &mut World) {
world.act();
}
}
struct World {
actors: Vec<Actor>,
state: u32
}
impl World {
pub fn step(&mut self) {
for actor in self.actors.iter_mut() {
actor.step(self);
}
}
pub fn act(&mut self) {
self.state += 1;
}
}
fn main() {
}
This code give the error:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:18:24
|
17 | for actor in self.actors.iter_mut() {
| ----------------------
| |
| first mutable borrow occurs here
| first borrow later used here
18 | actor.step(self);
| ^^^^ second mutable borrow occurs here
For more information about this error, try `rustc --explain E0499`.
error: could not compile `actors` due to previous error
You can't. It is impossible to mutate something while iterating over it, and in your current layout, Actor::step() would have the power to modify the actors list. So your situation is impossible, and Rust is correct that it shouldn't be allowed.
The real question is: Does your step function really require the list of actors? If not, I would solve the situation by splitting the list of actors and the state into two objects. That way, you can iterate over actors while only modifying state:
struct Actor {}
impl Actor {
pub fn step(&mut self, state: &mut WorldState) {
state.act();
}
}
struct WorldState {
some_value: u32,
}
struct World {
actors: Vec<Actor>,
state: WorldState,
}
impl World {
pub fn step(&mut self) {
for actor in self.actors.iter_mut() {
actor.step(&mut self.state);
}
}
}
impl WorldState {
pub fn act(&mut self) {
self.some_value += 1;
}
}
A somewhat simple solution is to pass exactly what you need.
impl Actor {
fn step(&mut self, state: &mut u32) {
*state += 1;
}
}
impl World {
pub fn step(&mut self) {
for actor in self.actors.iter_mut() {
actor.step(&mut self.state);
}
}
}

Unwrapping inner type from enum Rust multiple return type [duplicate]

This question already has answers here:
Unwrap inner type when enum variant is known
(4 answers)
Closed 7 months ago.
I have a function that returns an enum (an enum is used due to multiple possible return types).
But a method on one of the enum's variant type.
myTypeObject.print_type() <- This function call doesn't work
The code is below:
fn main() {
let myTypeObject = get_a_type(1);
myTypeObject.print_type();
}
struct TypeOne {
typename: String,
typeid: u8,
}
struct TypeTwo {
typename: String,
typeid: u8,
}
trait TraitOneTwo {
fn new(name: String) -> Self;
fn print_type(self);
}
impl TraitOneTwo for TypeOne {
fn new(name: String) -> Self {
Self {
typename: name,
typeid: 1,
}
}
fn print_type(self) {
println!("My type is: {}", self.typename);
}
}
impl TraitOneTwo for TypeTwo {
fn new(name: String) -> Self {
Self {
typename: name,
typeid: 2,
}
}
fn print_type(self) {
println!("My type is: {}", self.typename);
}
}
enum Types {
T1(TypeOne),
T2(TypeTwo),
}
fn get_a_type(desired_type: u8) -> Types {
if let 1 = desired_type {
return Types::T1(TypeOne::new(String::from("Foo")));
} else {
return Types::T2(TypeTwo::new(String::from("Bar")));
}
}
error[E0599]: no method named `print_type` found for enum `Types` in the current scope
--> src/main.rs:3:18
|
3 | myTypeObject.print_type();
| ^^^^^^^^^^ method not found in `Types`
...
45 | enum Types {
| ---------- method `print_type` not found for this
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `TraitOneTwo` defines an item `print_type`, perhaps you need to implement it
--> src/main.rs:16:1
|
16 | trait TraitOneTwo {
| ^^^^^^^^^^^^^^^^^
I have tried defining the type as below, which still throws an error:
fn main() {
let myTypeObject: TypeOne = get_a_type(1).try_into().unwrap();
myTypeObject.print_type();
}
Error:
error[E0277]: the trait bound `TypeOne: From<Types>` is not satisfied
--> src/main.rs:2:47
|
2 | let myTypeObject: TypeOne = get_a_type(1).try_into().unwrap();
| ^^^^^^^^ the trait `From<Types>` is not implemented for `TypeOne`
|
= note: required because of the requirements on the impl of `Into<TypeOne>` for `Types`
= note: required because of the requirements on the impl of `TryFrom<Types>` for `TypeOne`
= note: required because of the requirements on the impl of `TryInto<TypeOne>` for `Types`
How may I invoke the print_type() function?
You could match on the enum like so:
fn main() {
let myTypeObject = get_a_type(1);
match myTypeObject {
Types::T1(t1) => {
t1.print_type()
}
Types::T2(t2) => {
t2.print_type()
}
}
}
here is the full example in a playground.
But the function in that enum cannot be invoked.
The error seems entirely clear:
no method named print_type found for enum Types in the current scope
The enum Types literally has no methods, how could you call that one on it?
The compiler even suggests one way to fix the issue:
TraitOneTwo defines an item print_type, perhaps you need to implement it
Now that doesn't really work because your trait definition doesn't really make sense: why is new part of the trait? But if you move new to intrinsic impls and then implement your trait on the enum, it works fine, kind-of:
impl TraitOneTwo for Types {
fn print_type(self) {
match self {
Self::T1(one) => one.print_type(),
Self::T2(two) => two.print_type(),
}
}
}
It's not clear why you need both a trait and an enum though.
NB: you could also make print_type an intrinsic method of the enum, as well as do everything in it directly
impl Types {
fn print_type(&self) {
println!(
"My type is: {}",
match self {
Self::T1(one) => &one.typename,
Self::T2(two) => &two.typename,
}
);
}
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=dd097063943573b6d3b9c89643ba5a33
I don't really see the point of all the complexity, is this a java thing where you're supposed to use interfaces for everything?

Using * to dereference custom type implemented Deref trait raise error [duplicate]

Code:
use std::collections::HashSet;
use std::{mem, ptr, fmt};
use std::ops::Deref;
enum Unsafety {
Normal
}
enum ImplPolarity { Positive }
struct TraitRef;
struct Ty;
struct ImplItem;
enum ItemKind {
Impl(Unsafety,
ImplPolarity,
Option<TraitRef>, // (optional) trait this impl implements
Box<Ty>, // self
),
}
struct Item {
node: ItemKind,
}
pub struct P<T: ?Sized> {
ptr: Box<T>
}
impl<T: 'static> P<T> {
pub fn unwrap(self) -> T {
*self.ptr
}
}
impl<T: ?Sized> Deref for P<T> {
type Target = T;
fn deref(&self) -> &T {
&self.ptr
}
}
fn main() {
let mut items = Vec::<P<Item>>::new();
let mut item2: Item;
for item in items.drain(..) {
if let ItemKind::Impl(Unsafety::Normal,
ImplPolarity::Positive,
Some(ref trait_type),
ref for_type) = item.node {
} else {
// item2 = *item; // AAA
item2 = item.unwrap(); // BBB
}
}
}
Produce the compile-time error:
error[E0505]: cannot move out of `item` because it is borrowed
--> /home/xxx/.emacs.d/rust-playground/at-2017-07-29-204629/snippet.rs:64:21
|
61 | ref for_type) = item.node {
| ---- borrow of `item` occurs here
...
64 | item2 = item.unwrap();
I do not understand two things:
Why does it complain about the borrow in the if branch while we in else branch? They are supposed to be mutually exclusive, and a borrow in one should not influence another.
If I replace Vec in let mut items = Vec::<P<Item>>::new(); with Vec<Box<Item>> and uncomment line AAA and comment line BBB, then it compiles. Both Box and P implement Deref, so the item.node expression should be the same.
Here's a much clearer example:
struct Item;
struct P<T> {
ptr: Box<T>,
}
impl<T> P<T> {
fn new(v: T) -> Self {
P { ptr: Box::new(v) }
}
}
impl<T> std::ops::Deref for P<T> {
type Target = T;
fn deref(&self) -> &T {
&self.ptr
}
}
fn main() {
let mut item = P::new(Item);
// let mut item = Box::new(Item);
*item;
}
Both Box and P implement Deref, so the item.node expression should be the same.
Hard truth time: moving out of Box is special-cased in the compiler. It does not use Deref. Moving out of a Box deallocates the memory and gives you ownership. It is not possible to implement this special ability ourselves.
Maybe at some point in the future a hypothetical trait like DerefMove will be added. This trait is hard to get right. There have been a number of attempts for an RFC for it, but none are currently open.
See also:
Dereferencing Box<T> gives back value instead of reference
How can I reuse a box that I have moved the value out of?

Is there a way to get objects from a HashSet<Rc<T>> using a custom Borrow implementation other than creating a newtype?

I have a Student struct which I store in a HashSet inside a School struct wrapped by Rc references so that they can be referenced by other internal structures in School:
use std::collections::HashSet;
use std::hash::{Hash, Hasher};
use std::rc::Rc;
#[derive(Debug, Eq)]
struct Student {
id: usize,
// other stuff
}
impl Hash for Student {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl PartialEq for Student {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
struct School {
students: HashSet<Rc<Student>>,
// other stuff
}
impl School {
fn new() -> Self {
Self {
students: HashSet::new(),
}
}
fn add_student(&mut self) -> usize {
let id = self.students.len();
self.students.insert(Rc::new(Student { id }));
id
}
}
I wanted to implement Borrow<usize> for Rc<Student> so I could get references to students from the HashSet using their id:
use std::borrow::Borrow;
impl Borrow<usize> for Rc<Student> {
fn borrow(&self) -> &usize {
&self.id
}
}
impl School {
fn enrol(&mut self, student_id: usize) {
// Need trait Borrow<usize> implemented for Rc<Student> for this to work
if let Some(student) = self.students.get(&student_id) {
println!("Enrolling {:?}", student);
}
}
}
Unfortunately I can't do that as Borrow is defined elsewhere, and the compiler is telling me I need to create a new type.
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> src/main.rs:26:1
|
26 | impl Borrow<usize> for Rc<Student> {
| ^^^^^-------------^^^^^-----------
| | | |
| | | `std::rc::Rc` is not defined in the current crate
| | `usize` is not defined in the current crate
| impl doesn't use only types from inside the current crate
|
= note: define and implement a trait or new type instead
I understand why a direct implementation of Borrow for Rc<T> is not possible but I'm wondering if there is a better way other than defining a new type just so I can implement Borrow. The goal is to have a shared reference but still be able to get objects from the HashSet by their id? Perhaps Rc isn't the best option here?

How to implement a macro that defines a new public type and returns an instance of that type?

I want to implement a struct using macro_rules! because the generics require a lot of boilerplate and trait hunting.
The struct in question has a hash table inside but the key and the value types are to be provided by the user. The code is as follows:
macro_rules! new_ytz {
($T: ty) => {
// define the struct
pub struct Ytz {
table: hashbrown::hash_map::HashMap<$T, $T>,
}
impl Ytz {
pub fn new() -> Self {
Ytz {
table: hashbrown::hash_map::HashMap::<$T, $T>::new(),
}
}
pub fn add(&mut self, item: &$T) {
if self.table.contains_key(item) {
*self.table.get_mut(item).unwrap() += *item;
} else {
self.table.insert(*item, *item);
}
}
pub fn largest(&self) -> $T {
let mut result = 0;
for v in self.table.values() {
if result < *v {
result = *v;
}
}
result
}
}
// construct an instance of the struct and return it
Ytz::new()
};
}
// driver
fn main() {
let mut y = new_ytz!(u64); // should construct the object and return Ytz::new()
y.add(&71);
y.add(&25);
y.add(&25);
y.add(&25);
y.add(&34);
println!("{}", y.largest());
}
This won't compile since it tries to paste the struct within the main function:
error: expected expression, found keyword `pub`
--> src/main.rs:4:9
|
4 | pub struct Ytz {
| ^^^ expected expression
...
40 | let mut y = new_ytz!(u64); // should construct the object and return Ytz::new()
| ------------- in this macro invocation
How can I work around it? How can I paste the struct outside the main function publicly, along with the impl block?
generics require a lot of boilerplate
use std::collections::HashMap;
use core::hash::Hash;
use std::ops::AddAssign;
struct YtzU64<T: Eq + Ord + Hash + Copy + AddAssign> {
table: HashMap<T, T>
}
impl<T: Eq + Ord + Hash + Copy + AddAssign> YtzU64<T> {
pub fn new() -> Self {
Self {
table: HashMap::new()
}
}
pub fn add(&mut self, item: &T) {
if let Some(item) = self.table.get_mut(item) {
*item += *item;
} else {
self.table.insert(*item, *item);
}
}
pub fn largest(&self) -> Option<T> {
let mut values = self.table.values();
let mut largest:Option<T> = values.next().map(|t| *t);
for v in values {
if largest < Some(*v) {
largest = Some(*v);
}
}
largest
}
}
fn main() {
let mut y = YtzU64::new();
y.add(&71);
y.add(&25);
y.add(&25);
y.add(&25);
y.add(&34);
println!("{}", y.largest().unwrap());
}
My translation of your macro requires less boilerplate than your macro. It has two fewer indents, 4 fewer lines (macro_rules!, pattern matching at the top, two close braces at the end). Note that I changed the api slightly, as largest now returns an Option, to match std::iter::Iterator::max(). Also note that your api design is limited to T:Copy. You would have to redesign it a little if you want to support T: ?Copy + Clone or T: ?Copy + ?Clone.
trait hunting
The compiler is your friend. Watch what happens when I remove one of the trait bounds
error[E0277]: the trait bound `T: std::hash::Hash` is not satisfied
...
Using a macro is an interesting exercise, but re-implementing generics using macros is not useful.

Resources