Reputation: 806
The solution provided in question 38553513 does not work for me.
Consider these types and functions:
pub enum Parameter {
ParameterTypeA { n: i32 },
ParameterTypeB { s: String },
}
pub struct Res {
pub param: Parameter,
pub res: i32,
}
n use_string(_: String) -> i32 {
return 23;
}
fn use_int(_: i32) -> i32 {
return 42;
}
What I wanted to achieve was this:
fn foobar(p: Parameter) -> std::result::Result<Res, String> {
return match p {
Parameter::ParameterTypeA { n } => { Ok(Result { param: p, res: use_int(n) }) }
Parameter::ParameterTypeB { s } => { Ok(Result { param: p, res: use_string(s) }) }
};
}
But the compiler complained about Parameter::ParameterTypeB { s }
being partially moved and refuses to use it with param: p
.
According to the compiler's suggestion and the mentioned SO thread, I changed the second match to
Parameter::ParameterTypeB { ref s } => { Ok(Result { param: p, res: use_string(s.to_string()) }) }
but again, the compiler complains that {ref s}
borrows p.s
which cannot be moved while creating the result.
How is should this problem be solved? Please understand, modifying the function signatures or data types is not an option.
MVE available at play.rust-lang.org.
Upvotes: 0
Views: 102
Reputation: 23319
The most idiomatic way to fix this would be to change the signature of use_string
so that it takes a &str
instead of a String
:
pub enum Parameter {
ParameterTypeA { n: i32 },
ParameterTypeB { s: String },
}
pub struct Res {
pub param: Parameter,
pub res: i32,
}
fn use_string(_: &str) -> i32 {
return 23;
}
fn use_int(_: i32) -> i32 {
return 42;
}
fn foobar(p: Parameter) -> std::result::Result<Res, String> {
return match p {
Parameter::ParameterTypeA { n } => { Ok(Res { param: p, res: use_int(n) }) }
Parameter::ParameterTypeB { ref s } => { Ok(Res { res: use_string (s), param: p }) }
};
}
Note that I've changed the order of res
and param
so that res
comes first when instantiating Res
. This is because they are evaluated from left to right, and having param: p
first would move p
and make it impossible to use s
(which borrows p
) in the subsequent call to use_string
.
Since you state that changing the signature is not an option, you will need to clone the string so that p
retains a copy after the call to use_string
:
pub enum Parameter {
ParameterTypeA { n: i32 },
ParameterTypeB { s: String },
}
pub struct Res {
pub param: Parameter,
pub res: i32,
}
fn use_string(_: String) -> i32 {
return 23;
}
fn use_int(_: i32) -> i32 {
return 42;
}
fn foobar(p: Parameter) -> std::result::Result<Res, String> {
return match p {
Parameter::ParameterTypeA { n } => { Ok(Res { param: p, res: use_int(n) }) }
Parameter::ParameterTypeB { ref s } => { Ok(Res { res: use_string (s.clone()), param: p }) }
};
}
Upvotes: 1