Value moved on match, I do not understand why


#1

Hi Folks,

maybe I should have posted on SO, but I had the impression that here the conversations are deeper and more interesting, if it is not appropriate, please just tell me and I will move.

Anyway, I have this piece of code that I do not understand very well what is happening.

Given a Result<T, U>, I need to check that the result is actually an Ok(T) if it is I need to call a function on T, and based on the result of such function call another procedure.
Finally, no matter what, I need to call a third function on the initial Result.

Only the last function should take the property of the Result, all the intermediate procedure should just be able to read.

To make thing simpler, in code it looks like this:

fn return_value(client: BlockedClient, result: Result<QueryResult, err::RediSQLError>) {
    match result {
        Err(_) => {} // do nothing
        Ok(query_result) => match query_result.to_replicate() { //line 344
            false => {} // do nothing
            true => {
                // do something without touching `result`
                let ctx = ffi::RedisModule_GetThreadSafeContext.unwrap()(client.client);
                ffi::RedisModule_ReplicateVerbatim.unwrap()(ctx);
            }
        },
    }
    // we don't care of what happened before, now use result
    ffi::RedisModule_UnblockClient.unwrap()(
        client.client,
        Box::into_raw(Box::new(result)) as *mut std::os::raw::c_void, //line 362
    );
}

impl QueryResult {
    pub fn to_replicate(self) -> bool {
        // may return true or may return false
    }
}

Unfortunately this code does not compile:

error[E0382]: use of partially moved value: `result`
    --> src/redis.rs:362:79
     |
 344 |         Ok(query_result) => {
     |            ------------ value moved here
 ...
 362 |                                                        Box::into_raw(Box::new(result)) as *mut std::os::raw::c_void);
     |                                                                               ^^^^^^ value used here after move
     |
     = note: move occurs because `(result:std::prelude::v1::Ok).0` has type `redis::QueryResult`, which does not implement the `Copy` trait
 
 error: aborting due to previous error

I do not understand why the Ok() (/or the match) moves the value inside.

Can somebody enlight me?


#2

Yes, you can ask any question you want here!

Your function to_replicate takes self, so you are currently doing something with the value inside the result. It looks like (based on the function signature) your function might not need to do that, so try changing it to fn to_replicate(&self) to pass a reference instead of the value. Then, in your match arm, instead of moving the value out of result, you can take a reference like so: Ok(ref query_result) => ...


#3

Thanks, it was exactly the problem.

I though about it myself but it must have been a slighlty different code/test and it didn’t solve the issue.

Thanks again :slight_smile:


#4

As an aside, you can simplify (after making changes suggested by @jethrogb) :

Ok(ref query_result) => match query_result.to_replicate() { //line 344
            false => {} // do nothing
            true => {
                // do something without touching `result`
                let ctx = ffi::RedisModule_GetThreadSafeContext.unwrap()(client.client);
                ffi::RedisModule_ReplicateVerbatim.unwrap()(ctx);
            }
        },

to

Ok(ref query_result) if query_result.to_replicate() => {
                // do something without touching `result`
                let ctx = ffi::RedisModule_GetThreadSafeContext.unwrap()(client.client);
                ffi::RedisModule_ReplicateVerbatim.unwrap()(ctx);
            }

#5

Thank you :slight_smile: