Struct creation by mutating members?

In C++, a class can be created, and mutable methods on the self can be called in the Initialization function:

class App {
    private:
    int foo;
    float bar;
    void set_bar() {
        bar = (int)foo;
    }
    public:
    App() {
        foo = 0.0;
        set_bar();
    }
}

I understand that this can be done with options, and getter functions, but I am just wondering if there is a way to do this in rust without having to unwrap every time I want to access a member.

In Rust, the need for this isn’t all that common. Really, methods on a type usually are only used with fully constructed instances of that type. A method like set_bar() above, is that only used during construction? If so, it can easily work without actually needing a complete (but not yet fully “constructed”) value of type App… just return the field that’s computed – or if multiple values are involved, bundle them up with some tuple or other type.

Or is set_bar used both during construction, but also later during normal usage? Perhaps e.g. like some kind of (helper) method that sets up or restores an invariant? Yeah, I guess then it can make sense to fill the struct with some “dummy” data, and then call that same method afterwards.

If you want to avoid changing a field type to Option then … in your case, for a float, you can just initialize with some “garbage” like 0 I guess.

For a version of “Option” that’s really almost always not None, I guess one could define a type with an implicit unwrap in a Deref[/Mut] impl? This should avoid most of the annoyance around “too much unwrap required”; but I don’t think the need should come up all that often.

(I do however still wonder if such a type is already present in any common library or so, perhaps someone can link something interesting.)

But let’s get back to exploring the more Rusty way of constructing data: compute field values in helper functions if necessary and just pass them by value; use modules for privacy/visibility, so your free-standing helper functions needn’t be public anyway; then your example might turn out looking something like this:

pub mod app {
    pub struct App {
        foo: f32,
        bar: i32,
    }

    // this could take `foo` by-reference if it was
    // a more complex / less trivially copyable type ;-)
    fn compute_bar(foo: f32) -> i32 {
        foo as i32
    }

    impl App {
        pub fn new() -> Self {
            let foo = 0.0;
            let bar = compute_bar(foo);
            Self { foo, bar }
        }
    }
}

No, you can't have uninitialised fields without either safe wrapper like Option or unsafe one like MaybeUninit. Structs can exist in a partially moved-out-of state, but that's only for destructuring and doesn't allow method calls.

Rust usually solves this using a builder pattern — a version of the struct with optional fields that gets built and moved into a struct with all required fields. There are crates that help with the boilerplate:

1 Like