0

I have an immutable data structure, and an update function that takes ownership of the data structure and returns a new data structure:

enum Immutable {
    Item(i32)
}

fn update(imm: Immutable) -> Immutable {
    match imm {
        Immutable::Item(x) => Immutable::Item(x + 1)
    }
}

I need to store the data structure in a mutable field of a container:

struct State {
    item: Immutable
}

I want to write an imperative update function for State that calls the function updater:

fn update_mut(st: &mut State) -> () {
    let mut owned = Immutable::Item(42); // junk
    std::mem::swap(&mut st.item, &mut owned);
    st.item = update(owned);
}

This code works, but it seems sily to use mem::swap and allocate a junk object. I would really like to write:

fn update_mut_type_error(st: &mut State) -> () {
    let mut owned = Immutable::Item(42); // junk
    std::mem::swap(&mut st.item, &mut owned);
    st.item = update(st.item); // type error
}

Is there any way to address this? Or, do I have to use mem::swap here, even though it seems spurious.

Example on Rust Playground

Arjun Guha
  • 486
  • 4
  • 11
  • Neither of your example links work FYI. You probably forgot to make sharable links. – loganfsmyth Nov 15 '18 at 04:05
  • 3
    The case to consider is, what would happen if `update` were to panic? You'd have transferred `st.item` to `update`, so what value would be in `st.item` after the panic? It needs to be something or else the you're leaving your `State` object in an invalid state. Also good reading: http://smallcultfollowing.com/babysteps/blog/2018/11/10/after-nll-moving-from-borrowed-data-and-the-sentinel-pattern/ – loganfsmyth Nov 15 '18 at 04:11
  • 3
    The difference to the question tagged as duplicate is that the `update()` function requires to temporarily take ownership of `st.item` _while the new value is build_. This means the solutions based on `std::mem::replace()` and `std::mem::swap()` in the first answer won't work as written there. The best solution would be to change the interface of `update()` to take a reference instead, if possible. If not, I recommend reading [this blog post on the subject](http://smallcultfollowing.com/babysteps/blog/2018/11/10/after-nll-moving-from-borrowed-data-and-the-sentinel-pattern/). – Sven Marnach Nov 15 '18 at 12:11
  • Thanks, @SvenMarnach. That blog post has essentially the same example. `mem::swap` is slightly cleaner than my solution. – Arjun Guha Nov 15 '18 at 12:23

1 Answers1

-2

As Sven points out, this question is answered here:

http://smallcultfollowing.com/babysteps/blog/2018/11/10/after-nll-moving-from-borrowed-data-and-the-sentinel-pattern/

Arjun Guha
  • 486
  • 4
  • 11
  • 1
    Please don't post link-only answers. If you agree that your question is answered at [How can I swap in a new value for a field in a mutable reference to a structure?](https://stackoverflow.com/questions/27098694/how-can-i-swap-in-a-new-value-for-a-field-in-a-mutable-reference-to-a-structure), you can close it yourself -- there should be a "close" button underneath the post. If you don't see that, you might not have enough reputation; you don't need to do anything. If you don't believe your question is substantially the same as that one, you can answer it yourself, but... – trent Nov 15 '18 at 22:11
  • 1
    ... don't just post a link. Copy and quote the relevant portions of the article, and add any explanation that might be necessary to make your answer stand alone. Blogs can go down; Stack Overflow is interested in answers (and questions) that don't depend on external links. – trent Nov 15 '18 at 22:13