Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modify struct field inside of Option

Tags:

rust

I'm having problems in changing a field of a struct inside of option. This is the code:

struct MyStruct {
    field1 : i32,
    field2 : i32,
    // and many more...
}

impl MyStruct {
    pub fn field1(&mut self, field1 : i32) -> &mut Self {
        self.field1 = field1;
        self
    }
}

fn foo() -> Option<MyStruct> {
    None
}

fn bar() -> Option<MyStruct> {
    foo().as_mut().map(|s| s.field1(5))
}

fn main() {
    bar();
}

The main idea of bar() is to get an Option<MyStruct> from another function returning an Option<MyStruct>, change a field of that struct (in case the result is not None) and return the resulting Option<MyStruct>.

The struct implements the builder pattern, so I've used it.

In this case I get the following error:

test.rs:18:5: 18:40 error: mismatched types:
expected `core::option::Option<MyStruct>`,
    found `core::option::Option<&mut MyStruct>`
(expected struct `MyStruct`,
    found &-ptr) [E0308]
test.rs:18     foo().as_mut().map(|s| s.field1(5))

I've also tried to use Option.take() and to change the signature of the builder method as pub fn field1(mut self, field1 : i32) -> Self, but none of them work.

How can I make this code work?

I know that I could create another Option and map every field of the input to the corresponding field of the output, but MyStruct has a lot of fields and it is tedious.

like image 771
mbrt Avatar asked Aug 28 '15 12:08

mbrt


1 Answers

There is no reason to use as_mut() at all. Because you need to return MyStruct by value, you can just map on the option:

fn bar() -> Option<MyStruct> {
    foo().map(|mut s| { s.field1(5); s })
}

That's it. You need to mark s with mut for the same reason you need to do so with let.

like image 66
Vladimir Matveev Avatar answered Nov 15 '22 11:11

Vladimir Matveev