I have a struct:
pub struct Test {
pub x: i32,
pub y: i32,
}
I'd like to have a function that mutates this — easy:
pub fn mutateit(&mut self) {
self.x += 1;
}
This makes the entire struct mutable for the duration of the function call of mutateit, correct? I only want to mutate x, and I don't want to mutate y. Is there any way to just mutably borrow x?
Citing The Book:
Rust does not support field mutability at the language level, so you cannot write something like this:
struct Point {
mut x: i32, // This causes an error.
y: i32,
}
You need interior mutability, which is nicely described in the standard docs:
use std::cell::Cell;
pub struct Test {
pub x: Cell<i32>,
pub y: i32
}
fn main() {
// note lack of mut:
let test = Test {
x: Cell::new(1), // interior mutability using Cell
y: 0
};
test.x.set(2);
assert_eq!(test.x.get(), 2);
}
And, if you wanted to incorporate it in a function:
impl Test {
pub fn mutateit(&self) { // note: no mut again
self.x.set(self.x.get() + 1);
}
}
fn main() {
let test = Test {
x: Cell::new(1),
y: 0
};
test.mutateit();
assert_eq!(test.x.get(), 2);
}
Related
I'm making a maze algorithm using rust and wasm and I have two structs. A maze, and maze has an Vec of a Block struct.
Like this:
pub struct Maze {
pub cols: usize,
pub rows: usize,
pub blocks: Vec<Block>,
pub stack: Vec<usize>,
}
impl Maze {
pub fn new(cols: usize, rows: usize) -> Maze {
let mut maze = Maze {
cols,
rows,
blocks: vec![],
};
for y in 0..rows {
for x in 0..cols {
maze.blocks.push(Block::new(x, y))
}
}
maze
}
And the struct Block has an attribute called visited.
I want in a struct function of Maze change this value
// in Maze struct impl
pub fn run(&mut self) {
let current_index = self.get_current_index();
let mut current_block = &mut &self.blocks[current_index];
// .....
*current_block.visited = true;
In the last line occur an error:
error[E0614]: type `bool` cannot be dereferenced
--> src/maze.rs:119:17
|
119 | *current_block.visited = true;
| ^^^^^^^^^^^^^^^^^^^^^^
How can I do to change this value?
This is my implementation of Block
pub struct Block {
pub x: usize,
pub y: usize,
pub visited: bool,
}
impl Block {
pub fn new(x: usize, y: usize) -> Block {
Block {
x,
y,
visited: false,
}
}
How can I do to change the visited value from Maze.run?
There are two problems, one which is the error you see and one which you will encounter next. The problem with
*current_block.visited = true;
is that the precedence of * is lower than ., so you've written code equivalent to)
*(current_block.visited) = true;
which does not compile because the type of the visited field is bool, which indeed cannot be dereferenced. You could write
(*current_block).visited = true;
and that would work, but it's also unnecessary, because in Rust the . operator looks through references, so you only need
current_block.visited = true;
to assign to the visited field of an &mut Block.
The second problem is that you have an extra & here:
let mut current_block = &mut &self.blocks[current_index];
This means current_block is of type &mut &Block. You can never mutate through an & reference, so you need to remove the &, and it is not needed anyway:
let mut current_block = &mut self.blocks[current_index];
I'm working with two crates: A and B. I control both. I'd like to create a struct in A that has a field whose type is known only to B (i.e., A is independent of B, but B is dependent on A).
crate_a:
#[derive(Clone)]
pub struct Thing {
pub foo: i32,
pub bar: *const i32,
}
impl Thing {
fn new(x: i32) -> Self {
Thing { foo: x, bar: &0 }
}
}
crate_b:
struct Value {};
fn func1() {
let mut x = A::Thing::new(1);
let y = Value {};
x.bar = &y as *const Value as *const i32;
...
}
fn func2() {
...
let y = unsafe { &*(x.bar as *const Value) };
...
}
This works, but it doesn't feel very "rusty". Is there a cleaner way to do this? I thought about using a trait object, but ran into issues with Clone.
Note: My reason for splitting these out is that the dependencies in B make compilation very slow. Value above is actually from llvm_sys. I'd rather not leak that into A, which has no other dependency on llvm.
The standard way to implement something like this is with generics, which are kind of like type variables: they can be "assigned" a particular type, possibly within some constraints. This is how the standard library can provide types like Vec that work with types that you declare in your crate.
Basically, generics allow Thing to be defined in terms of "some unknown type that will become known later when this type is actually used."
Given the example in your code, it looks like Thing's bar field may or may not be set, which suggests that the built-in Option enum should be used. All you have to do is put a type parameter on Thing and pass that through to Option, like so:
pub mod A {
#[derive(Clone)]
pub struct Thing<T> {
pub foo: i32,
pub bar: Option<T>,
}
impl<T> Thing<T> {
pub fn new(x: i32) -> Self {
Thing { foo: x, bar: None }
}
}
}
pub mod B {
use crate::A;
struct Value;
fn func1() {
let mut x = A::Thing::new(1);
let y = Value;
x.bar = Some(y);
// ...
}
fn func2(x: &A::Thing<Value>) {
// ...
let y: &Value = x.bar.as_ref().unwrap();
// ...
}
}
(Playground)
Here, the x in B::func1() has the type Thing<Value>. You can see with this syntax how Value is substituted for T, which makes the bar field Option<Value>.
If Thing's bar isn't actually supposed to be optional, just write pub bar: T instead, and accept a T in Thing::new() to initialize it:
pub mod A {
#[derive(Clone)]
pub struct Thing<T> {
pub foo: i32,
pub bar: T,
}
impl<T> Thing<T> {
pub fn new(x: i32, y: T) -> Self {
Thing { foo: x, bar: y }
}
}
}
pub mod B {
use crate::A;
struct Value;
fn func1() {
let mut x = A::Thing::new(1, Value);
// ...
}
fn func2(x: &A::Thing<Value>) {
// ...
let y: &Value = &x.bar;
// ...
}
}
(Playground)
Note that the definition of Thing in both of these cases doesn't actually require that T implement Clone; however, Thing<T> will only implement Clone if T also does. #[derive(Clone)] will generate an implementation like:
impl<T> Clone for Thing<T> where T: Clone { /* ... */ }
This can allow your type to be more flexible -- it can now be used in contexts that don't require T to implement Clone, while also being cloneable when T does implement Clone. You get the best of both worlds this way.
I am trying to add a member of a structure that is itself a structure. I have the classic mistake "can not move out of borrowed content".
How can I get around the problem
thanks in advance.
use std::cell::RefCell;
pub struct Sprite {
pub x: f32,
pub y: f32,
}
impl Sprite {
pub fn new(x: f32, y: f32) -> Sprite {
let sprite: Sprite = Sprite { x: x, y: y };
sprite
}
}
pub struct Human {
pub x: f32,
pub y: f32,
pub sprite: Sprite,
}
impl Human {
pub fn new() -> Human {
Human {
x: 400.0,
y: 300.0,
sprite: Sprite::new(1.0, 1.0),
}
}
}
pub struct Game {
pub human: Human,
sprites: Vec<RefCell<Sprite>>,
}
impl Game {
pub fn new() -> Game {
let human = Human::new();
Game {
human: human,
sprites: vec![],
}
}
pub fn init(&mut self) {
let sprite = self.human.sprite; //error : can not move out of borrowed content
self.create_sprite(sprite);
}
fn create_sprite(&mut self, sprite: Sprite) {
self.sprites.push(RefCell::new(sprite));
}
}
fn main() {}
I made the change proposed by RLS, which only displaced the problem.
I also tried to change the "lifetime" with annotations, it did not work either, but maybe I am wrong. I do not know this feature well.
REM : The code is purge for shows the error and compiled
Right, so your:
let sprite = human.sprite
Attempts to take ownership of the sprite field away from the human it is defined in.
This is prohibited in rust since it would leave a dangling reference in the struct if the original reference is destroyed, or double references if copied. Both unsafe.
Using a borrow allows simpler code semantics but borrows are supposed to have a specific lifetime, i.e. in general not stick around since the thing you are borrowing from might outlive the borrow reference otherwise.
The final option that's typically used is just copying the data, but since it seems you want to track the full state of your sprites from several places that wouldn't work here. Copying data would not leave a reference to the original.
There are ways around this in Rust.
So, since it seems to me you want to be able to reference the same Sprite-struct from two locations you need a lot of wrapping here.
I´ve added reference counting to your RefCell, this Rc wrapper can then be cloned and kept as a reference to the original Struct in several places.
The RefCell then provides the actual read-write "lock" to allow the data to be mutated from several places.
Have a look below and see if this brings you closer to your usecase:
use std::rc::Rc;
use std::cell::RefCell;
pub struct Sprite {
pub x: f32,
pub y: f32,
}
impl Sprite {
pub fn new(x: f32, y: f32) -> Sprite {
let sprite: Sprite = Sprite { x: x, y: y };
sprite
}
}
pub struct Human {
pub x: f32,
pub y: f32,
pub sprite: Rc<RefCell<Sprite>>,
}
impl Human {
pub fn new() -> Human {
Human {
x: 400.0,
y: 300.0,
sprite: Rc::new(RefCell::new(Sprite::new(1.0, 1.0))),
}
}
}
pub struct Game {
pub human: Human,
sprites: Vec<Rc<RefCell<Sprite>>>,
}
impl Game {
pub fn new() -> Game {
let human = Human::new();
Game {
human: human,
sprites: vec![],
}
}
pub fn init(&mut self) {
let sprite = self.human.sprite.clone(); //error : can not move out of borrowed content
self.create_sprite(sprite);
}
fn create_sprite(&mut self, sprite: Rc<RefCell<Sprite>>) {
self.sprites.push(sprite);
}
}
fn main() {}
I was playing around with updating a Rust struct in place using chained methods. I found a way to do this, but I was not sure if my code below was idiomatic Rust versus just a workaround.
In particular, I used .to_owned() at the end of the chained method to return the borrowed struct. The code compiles and works just fine. Here is the minimal example.
//struct.rs
#[derive(Debug, Default, Clone, PartialEq)]
pub struct ModelDataCapture {
run: i32,
year: i32,
}
impl ModelDataCapture {
pub fn new() -> Self {
ModelDataCapture::default()
}
pub fn set_run(&mut self, run: i32) -> &mut ModelDataCapture {
self.run = run;
self
}
pub fn set_year(&mut self, year: i32) -> &mut ModelDataCapture {
self.year = year;
self
}
}
//main.rs
let data_capture = ModelDataCapture::new()
.set_run(0)
.set_year(1)
.to_owned(); // <<< QUESTION
println!("here is the data capture {:?}", data_capture);
Is this the proper way to write this in-place modification of the struct? If I do not include the .to_owned() method at the end of the chain, the compile fails with a message that the temporary variable does not live long enough.
Your code "works" but doesn't make sense to me. It:
Creates a value
Mutates the value
Clones the value
Throws away the original value
See the inefficiency? In addition, all the "in-place mutation" is completely discarded, so there's no benefit to it.
I'd generally introduce a binding to mutate:
let mut data_capture = ModelDataCapture::new();
data_capture.set_run(0).set_year(1);
Or go all the way and create a builder that has some equivalent of finish or build
#[derive(Debug)]
struct ModelDataCapture {
run: i32,
year: i32,
}
#[derive(Debug, Default)]
struct ModelDataCaptureBuilder {
run: i32,
year: i32,
}
impl ModelDataCaptureBuilder {
fn set_run(self, run: i32) -> Self {
ModelDataCaptureBuilder { run, ..self }
}
fn set_year(self, year: i32) -> Self {
ModelDataCaptureBuilder { year, ..self }
}
fn build(self) -> ModelDataCapture {
let ModelDataCaptureBuilder { run, year } = self;
ModelDataCapture { run, year }
}
}
fn main() {
let data_capture = ModelDataCaptureBuilder::default().set_run(0).set_year(1).build();
println!("here is the data capture {:?}", data_capture);
}
See Do Rust builder patterns have to use redundant struct code? for more examples of builders that mirror the built items.
You could take self by-value in the first example, but that's annoying in most cases, as you always have to remember to bind the result.
You could change the function to take ownership over self and return self.
Because each "setter" method returns the ownership of self, this code should work out nicely.
For more information, please checkout the rust book
//struct.rs
#[derive(Debug, Default, Clone, PartialEq)]
pub struct ModelDataCapture {
run: i32,
year: i32,
}
impl ModelDataCapture {
pub fn new() -> Self {
ModelDataCapture::default()
}
pub fn set_run(mut self, run: i32) -> ModelDataCapture {
self.run = run;
self
}
pub fn set_year(mut self, year: i32) -> ModelDataCapture {
self.year = year;
self
}
}
fn main() {
//main.rs
let data_capture = ModelDataCapture::new().set_run(0).set_year(1);
println!("here is the data capture {:?}", data_capture);
}
How do I declare a "static" field in a struct in Rust, preferably with a default value:
struct MyStruct {
x: i32, // instance
y: i32, // instance
my_static: i32 = 123, // static, how?
}
fn main() {
let a = get_value();
if a == MyStruct::my_static {
//...
} else {
//...
}
}
You can declare an associated constant in an impl:
struct MyStruct {
x: i32,
y: i32,
}
impl MyStruct {
const MY_STATIC: i32 = 123;
}
fn main() {
println!("MyStruct::MY_STATIC = {}", MyStruct::MY_STATIC);
}
Rust does not support static fields in structures, so you can't do that. The closest thing you can get is an associated method:
struct MyStruct {
x: i32,
y: i32,
}
impl MyStruct {
#[inline]
pub fn my_static() -> i32 {
123
}
}
fn main() {
let a = get_value();
if a == MyStruct::my_static() {
//...
} else {
//...
}
}
You can't declare a field static in a struct.
You can declare a static variable at module scope like this :
static FOO: int = 42;
And you can't have a static variable mutable without unsafe code : to follow borrowing rules it would have to be wrapped in a container making runtime borrowing checks and being Sync, like Mutex or RWLock, but these cannot be stored in static variable as they have non-trivial constructors.