'Why does match will not release the mutable borrow until end of it's expression?
I want to return client, In this function in any circumstances the code will not continue after match so rust should allow returning client.
pub async fn call_query2(mut client: Client<Compat<TcpStream>>, query:&str) -> Result<(Vec<tiberius::Row>,Client<Compat<TcpStream>>),(tiberius::error::Error,Client<Compat<TcpStream>>)> {
match client.query(query, &[]).await {
Ok(stream) =>{
match stream.into_first_result().await {
Ok(rows) => Ok((rows,client)),
Err(e) => Err((e,client))
}
},
Err(e) => Err((e,client))
}
}
but the compiler return this error message:
match client.query(query, &[]).await {
| ------------------------------
| |
| borrow of `client` occurs here
| a temporary with access to the borrow is created here ...
...
102 | Err(e) => Err((e,client))
| ^^^^^^ move out of `client` occurs here
103 | }
104 | }
| - ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Result<QueryStream<'_>, tiberius::error::Error>`
It seems that match will not release the mutable borrow until end of it's expression, because this code will work but I'm not able to return client:
pub async fn call_query(mut client: Client<Compat<TcpStream>>, query:&str) -> Result<(Vec<tiberius::Row>,Client<Compat<TcpStream>>),tiberius::error::Error> {
let stream = client.query(query, &[]).await?;
return Ok((stream.into_first_result().await?, client));
}
Any idea?
Solution 1:[1]
The main thing is that the temporary value that is created with the match expression is not dropped (through the Drop trait) until after the match-expression. In a sense you can think of the code being something like this:
pub async fn call_query2(mut client: Client<Compat<TcpStream>>, query:&str) -> Result<(Vec<tiberius::Row>,Client<Compat<TcpStream>>), (tiberius::error::Error,Client<Compat<TcpStream>>)> {
let result;
let tmp = client.query(query, &[]).await;
match tmp {
Ok(stream) => {
match stream.into_first_result().await {
Ok(rows) => result = Ok((rows,client)),
Err(e) => result = Err((e,client))
}
},
Err(e) => result = Err((e,client))
}
// tmp.drop(); happens here implicitly
return result;
}
Note that the implicit call tmp.drop() here theoretically might need access to client from the borrow checker's perspective.
Your other example works because you're basically dropping result before the return statement. Conceptually something like this:
pub async fn call_query(mut client: Client<Compat<TcpStream>>, query:&str) -> Result<(Vec<tiberius::Row>,Client<Compat<TcpStream>>),tiberius::error::Error> {
let result = client.query(query, &[]).await;
if let Err(e) = result {
return Err( e );
}
let stream = result.unwrap();
return Ok((stream.into_first_result().await?, client));
}
Note that you couldn't return an Err( (e,client) ) inside the if here either or you'd get again the same error from the borrow checker, since result hasn't been dropped yet.
That being said -- why would you want to return client in the first place? Probably because you want to use client in the calling code again. But then your function shouldn't require the caller to give up ownership to client in the first place. Just change mut client: ... in the signature of your function to client: &mut ... and remove Client from the return value type like this:
pub async fn call_query2(client: &mut Client<Compat<TcpStream>>, query:&str) -> Result<Vec<tiberius::Row>, tiberius::error::Error> {
// same code as before, but changing the result so that
// it doesn't return client anymore, i.e,
// Ok( (rows,client) ) => Ok(rows) and same for Err
}
Now your calling code can still refer to client without needing it "passed back" from you function. I.e., you go from
if let Ok( (rows, old_new_client) ) = call_query(client, query) {
old_new_client.whatever();
}
to a much nicer
if let Ok(rows) = call_query2(&mut client, query) {
client.whatever();
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
