Question about code use

I’ve been looking at some Rust code lately and ran into some code that I had a few questions about.

struct A {
  field_1: u32,
  field_2: u32,
  field_3: u32,
  field_4: u32,
  field_5: u32,
}

struct B {
  field_1: u32,
  field_2: u32,
  field_3: u32,
}

impl A {
  fn b(self) -> B {
    let A {
      field_1,
      field_2,
      field_3,
      ..
    } = self;

    B {
      field_1,
      field_2,
      field_3,
    }
  }
}

The part I’m not quite sure about is the let A {} = self; code. Is that just making fields 1 -> 3 available so they can be used in B without having to write it like this?

B {
  field_1: self.field_1,
  field_2: self.field_2,
  field_3: self.field_3,
}

Is it mainly for a readability sort of thing, or does let A {} = self; do something more behind the scenes? I tried looking into this, but I’m not really sure what this would be called in rust. Does this technique have a name, and is it common to see code like this?

This is called destructuring, and is the same idea as in match statement patterns and if let patterns.

Except that this is an irrefutable pattern, meaning that it is impossible that this is not the case, because you’re only using named bindings. Therefore, self is consumed and turned into the named bindings that are defined in the pattern. This allows us to move multiple pieces of owned data out of the same object all at once in this case. But that doesn’t really matter all that much, given that the data types we’re talking about which is Copy and therefore could be copied out of self, but that’s not the point.

Also, this is very idiomatic code.

1 Like

Thanks for the quick response and actual name for this technique. That actually makes sense. In code I saw this example for, almost all the fields of the struct were Strings, I just used u32 to make the example simpler.

Since the actual example code uses String, and that doesn’t implement Copy, I’m assuming without that syntax, you would also have to add a clone to each of fields in order to assign it correctly in B?

Yes, because if we were to use a referenced destructuring then we’d have ended up with references to data that would have been dropped by the end of the function (with the data being held in self which is dropped because this function takes ownership of self). If we’d have forced it to be copied (As in bit by bit without a thought of the data underneath) then when we drop self we would have also dropped the data under the String (remember that string is a smart pointer) and returned the String whose pointed data is now invalidated.

Thanks for taking the time to explain all of that. I hadn’t really encountered code like this before and wasn’t sure where to look.

1 Like