Hello there,
I've trying to write a set a functions that can take either a &str
or a &mut Statement
as parameter.
I ended up with:
-
An enum
StatementRef<'r>
that can hold either types, -
The
From
trait is implemented for both types -
A function that need to support either types can be implented like this:
fn my_function<'s, S: Into<StatementRef<'s>> + 's>(statement: S) { let statement_ref: StatementRef = statement.into(); match statement_ref { StatementRef::Str(s) => { // a &str } StatementRef::Statement(statement) => { // a &mut Statement statement.inc(); } }
The code was working as expected until I tried to use the function twice in a row with a statement:
let mut statement = Statement {};
my_function(&mut statement); // ok
my_function(&mut statement); // error[E0499]: cannot borrow `statement` as mutable more than once at a time
I think this is related to the lexical lifetimes and
there's probably no work-around about it for now, but since I'm still a newbie in RUST I'm posting my example bellow so
someone can check if I didn't messed up with the lifetimes...
Example
Code also available in the playground.
pub struct Statement<'s> {
phantom: std::marker::PhantomData<&'s ()>,
counter: u32,
}
impl Statement<'_> {
pub fn inc(&mut self) {
self.counter += 1;
}
}
// An enum that can hold either a `&str` or a `&'r mut Statement<'_>`
pub enum StatementRef<'r> {
Str(&'r str),
Statement(&'r mut Statement<'r>),
}
//
// From is implemeted for both enum possible values
//
impl<'r, 's: 'r> From<&'s str> for StatementRef<'r> {
fn from(s: &'s str) -> Self {
StatementRef::Str(s)
}
}
impl<'r, 's: 'r> From<&'s mut Statement<'r>> for StatementRef<'r> {
fn from(statement: &'s mut Statement<'r>) -> Self {
StatementRef::Statement(statement)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn use_statement(statement: &mut Statement) {
statement.inc();
}
fn use_statement_ref<'s, S: Into<StatementRef<'s>> + 's>(statement: S) {
let statement_ref: StatementRef = statement.into();
match statement_ref {
StatementRef::Str(s) => {
println!("StatementRef::Str: {}", s);
}
StatementRef::Statement(statement) => {
println!("StatementRef::Statement: {}", statement.counter);
statement.inc();
}
}
}
#[test]
fn test() {
let mut a_statement = Statement {
phantom: std::marker::PhantomData,
counter: 0,
};
use_statement(&mut a_statement); // <-- mutable borrow scope limited to this function
use_statement_ref(&mut a_statement); // <--+ mutable borrow scope extends until the end of the function
use_statement_ref(&mut a_statement); // |
} // <-----------------------------------------+
}