8

I have a big object that I need boxed in another object but I don't necessarily need it all the time. So I want to use an if statement to get the optional boxed TempStructure but i'm not exactly sure how I can destructure and dereference at the same time.

Example:

pub struct TempStructure {
    lots_of_data: [u64; 64],
}
pub struct Structure {
    pending_removal: Option<Box<(TempStructure, bool)>>,
}
impl Structure {
    pub fn do_somthing(&mut self) {
        // How do I destructure the Option and dereference the Box to get TempStructure?
        if let Some((temp_structure, some_boolean)) = self.pending_removal.take() { 
            // Do something with temp_structure and some_boolean
        }
    }
}

When I do this ^^^ I get an expected struct `std::boxed::Box`, found tuple error.

Zyansheep
  • 168
  • 2
  • 11

2 Answers2

9

Dereference the box after matching:

if let Some(inner) = self.pending_removal.take() {
    let (temp_structure, some_boolean) = *inner;
    // Do something with temp_structure and some_boolean
}

(playground)

If you think this is a bit clunky, you're right. On nightly you can use the unstable box_patterns feature to enable a better syntax for this (although this might never be stabilized):

if let Some(box (temp_structure, some_boolean)) = self.pending_removal.take() {
    // Do something with temp_structure and some_boolean
}

(playground)

smitop
  • 4,770
  • 2
  • 20
  • 53
7

You can fix this with adding a .as_deref() after the take():

pub struct TempStructure {
    lots_of_data: [u64; 64],
}
pub struct Structure {
    pending_removal: Option<Box<(TempStructure, bool)>>,
}
impl Structure {
    pub fn do_somthing(&mut self) {
        // How do I destructure the Option and dereference the Box to get TempStructure?
        if let Some((temp_structure, some_boolean)) = self.pending_removal.take().as_deref() { 
            // Do something with temp_structure and some_boolean
        }
    }
}

Box<T> dereferences to &T, as_deref() dereferences the value of the Option, therefore it gives you a &T out of your Option<Box<T>>.

Edit: another option is to dereference the Box to move the value out of it:

        if let Some((temp_structure, some_boolean)) = self.pending_removal.take().map(|boxed| *boxed) { 
            // assignments just for demonstration purposes that we now get
            // owned values rather than references.
            let _: TempStructure = temp_structure;
            let _: bool = some_boolean;
        }
sebpuetz
  • 2,430
  • 1
  • 7
  • 15
  • I think I'm looking to move the tuple out of the box, not just get a reference to a temporary object. Is there any way I can do that with the `.as_deref()` function? – Zyansheep Mar 15 '21 at 12:50
  • 1
    You can move out of the box by dereferencing: ```Rust if let Some((temp_structure, some_boolean)) = self.pending_removal.take().map(|boxed| *boxed) { let _: TempStructure = temp_structure; let _: bool = some_boolean; // Do something with temp_structure and some_boolean } ``` – sebpuetz Mar 15 '21 at 13:02
  • That would be a good alternative to add to the answer. – trent Mar 15 '21 at 13:02
  • I edited the answer, missing a bit of experience in writing comments on SO, any clue how to fix the code block in the comment above? – sebpuetz Mar 15 '21 at 13:05
  • 2
    I don't think comments are supposed to have multiline code blocks. https://meta.stackexchange.com/questions/39260/how-do-i-post-code-in-comments – Zyansheep Mar 15 '21 at 13:06
  • I don't quite understand the last snippet. Why do you move from `temp_structure` and `some_boolean` to `_` (which discards them) and then have a comment that says "Do something with temp_structure and some_boolean"? Does that actually work? Or is the comment meant to be _before_ the `let` assignments? – user4815162342 Mar 15 '21 at 15:06
  • The assignments are just supposed to show that the type of `temp_structure` is now `TempStructure` and `some_boolean` is `bool` and not references as it's the case with `as_deref()`. I'll edit my answer and remove the comment, I didn't even realize it was there :) – sebpuetz Mar 15 '21 at 15:15