MFlamer
MFlamer

Reputation: 2440

Mutable Struct Fields

I know mutable fields were removed in 0.6. I'm getting the following error with this code,

C:\Users\mflamer\Dropbox\Rust\Tests\gmap.rs:23:8: 23:18 error: assigning to immutable field C:\Users\mflamer\Dropbox\Rust\Tests\gmap.rs:23 dart.alpha = vec::from_elem(self.n + 1, dart);

What am I doing wrong here? Thanks.

pub struct GMap<T> {
        priv     n: uint,
        priv darts: ~[Dart<T>]
    }

struct Dart<T> {
    alpha: ~[@Dart<T>],
    embed: ~[@T],
   tagged: bool
}

impl<T> GMap<T> {
    pub fn new(dim: uint) -> GMap<T> {      
        let mut map: GMap<T> = GMap{n: dim, darts: ~[]};
        return map
    }
    pub fn new_dart(&self, ) -> @Dart<T> {
        let mut dart = @Dart{alpha: ~[], embed: ~[], tagged: false};        
        dart.alpha = vec::from_elem(self.n + 1, dart); 
        //dart.embed = vec::from_elem(self.n + 1, );
        return dart;
    }
    pub fn dim(&self) -> uint {
        self.n 
    }
}


//pub fn traverse(&self,[bool,..])


enum Cell {
    Null,
    Vertex,
    Edge,
    Face,
    Solid
}   

fn main() { 
    let topo: GMap<Cell> = GMap::new(3);    
}

Upvotes: 4

Views: 11604

Answers (1)

huon
huon

Reputation: 102006

The problem is how mutability inherits via ownership. For something to be mutable, its owner has to be mutable. Ownership inherits except through a new owner, and @ and & are classified as owner. So in this case, you have dart owning the @Dart box, but not the contents of the box, so the mut on x doesn't imply that the contents of the box is mutable (indeed, it can't be mutable, since otherwise it could change under the feet of something else that refers to it).

The way to get around this is to either make the box a mutable box, so that the owner of the dart struct is mutable i.e. @mut Dart { .. } (this has a (small) runtime penalty, and can make the program fail, if it is mutated while borrowed as immutable), or construct it in one go. The former is non-optimal, and the latter sounds hard to achieve. However, the former might look like:

struct Dart<T> {
    alpha: ~[@mut Dart<T>],
    embed: ~[@T],
   tagged: bool
}

// ...

    pub fn new_dart(&self, ) -> @mut Dart<T> {
        let dart = @mut Dart{alpha: ~[], embed: ~[], tagged: false};        
        dart.alpha = vec::from_elem(self.n + 1, dart); 
        //dart.embed = vec::from_elem(self.n + 1, );
        return dart;
    }

(What's required for the non-@mut solution is "tying the knot", but it's not clear to me how to get it to work in Rust.)

Upvotes: 6

Related Questions