Declare a struct with generated & user-given data


#1

Hi,

I’m new to Rust, and now I’m trying to make a simple demo project. Now, I’m trying to do anything like this:

struct Anything {
    V1: i64,
    V2: i64,
}

impl Anything {
    fn new() -> Anything {
        Anything {
			V1: 10 + 10
		}
    }
}

fn main() {
    let var = Anything::new() {
		V2: 40
	};
    println!("Result: {}", var.V1 + var.V2);
    // Result: 60
}

…but I really don’t know how to do it. I’ve tried various times here, but without success. Is it possible? If not, is there any (idiomatic) way to do anything like this?


#2

In safe Rust a structure cannot exist in a half-uninitialized state, so your new() must produce a full, complete structure, or at least initialize all fields to some default/placeholder values.

One option is to require all input before the object is created:

   fn new(other_value: i64) -> Anything {
        Anything {
			V1: 10 + 10, 
			V2: other_value,
		}
    }

To simplify initialization of structures Rust has Default trait and Struct {..default_values} syntax. You can implement Default trait for your structure.

With #[derive(Default)] you can use a built-in Default implementation, which makes everything 0:

#[derive(Default)]
struct Anything {

…

        Anything {
			V1: 10 + 10,
			..Default::default()
		}
…

let mut var = Anything::new(); 
var.V2 = 40

or you can even write your own impl Default for Anything and make V1: 20 the default, so the final code could look like:

let var: Anything {
    V2: 40,
    ..Default::default(),
};

#3

I’ve already tested the fn (other_value: i64) method, but sometimes the user can add nothing as the “V2” value, so I wanted an option that allows the user to simply ignore the “V2” and use a placeholder value to be filled on another function. Using a already-placed value seemed as a “unnecessary overhead” at runtime, since all the data on the struct will be filled by a user or by the program itself (Ok, probably rustc can optimize it, but…).

However, using ..Default::default() worked without problems. Thank you very much, and sorry for taking so long to answer back. Here’s my code, with some testing of ..Default::default():

#[derive(Default)]
struct Anything {
    V1: i64,
    V2: i64,
    V3: i64,
}

impl Anything {
    fn new() -> Anything {
        Anything { V1: 10 + 10, ..Default::default() }
    }
    fn V3(&mut self, other_value: i64) -> Anything {
        Anything { V3: other_value, ..Default::default() }
    }
}

fn main() {
    let mut var = Anything::new();
    var.V2 = 40;
    var.V3(20);
    println!("V1: {}\nV2: {}\nV3: {}\nResult: {}",
             var.V1,
             var.V2,
             var.V3,
             var.V1 + var.V2 + var.V3);
    // Expected Result: 80 (20 + 40 + 20)
    // If error, Expected: 20 (0 + 0 + 20)
    // Actual Result: 60 (20 + 40 + 0)
}

Ok, It isn’t working as expected, but I will search more about this. Thank you very much!


#4

Ok, just one more question: Is there a way to modify more than one value of the struct? (I’ve tried using ..Default::default() on “V3”, but it didn’t work (the value tried to modify remained “0”).


#5

Your V3 function does not modify Anything, but returns a completely new object. It should be

fn V3(&mut self, other_value: i64) {
   self.V3 = other_value;
}

#6

I’ve forgotten of it. But I’ve added this just for testing, because I want to modify more than one struct without repeating “Anything.”. I know that I can do anything like this:

fn V3(&mut self, any_value: i64, other_value: i64) {
        Anything.V2 = any_value,
        Anything.V3 = other_value
    }

…but using Anything. every time I want to modify a value is repetitive, even when I want to modify various values at the same time.


#7

See https://doc.rust-lang.org/stable/book/structs.html#update-syntax

You can specify multiple fields:

Anything { V1: one_value, V3: other_value, ..Default::default() }

or base the new value on the old instance rather than the defaults:

Anything { V3: other_value, ..*self }

(you may have to #[derive(Clone, Copy)] for that one)


#8

This doesn’t work anyway, it should be self.V2 = any_value etc. And no, there is no shorthand to avoid writing self in this case.

When you want to replace most values, you can do

*self = Anything { V1: xxx, V2: yyy };

in a &mut self method.


#9

@kevinmehall and @birkenfeld, thank you for the help. Using both *self and ..*self is working fine:

#[derive(Default)]
struct Anything {
    v1: i64,
    v2: i64,
    v3: i64,
}

impl Anything {
    fn new() -> Anything {
        Anything { v1: 10 + 10, ..Default::default() }
    }
    fn v3(&mut self, any_value: i64, other_value: i64) {
        *self = Anything {
            v2: any_value,
            v3: other_value,
            ..*self
        }
    }
}

fn main() {
    let mut var = Anything::new();
    var.v2 = 40;
    var.v3(60, 20);
    println!("V1: {}\nV2: {}\nV3: {}\nResult: {}",
             var.v1,
             var.v2,
             var.v3,
             var.v1 + var.v2 + var.v3);
    // Result: 100 (20 + 60 + 20)
}