避免在匹配语句中使用部分移动的值
Avoid using partially moved value in match statement
问题中提供的解决方案对我不起作用。
考虑这些类型和函数:
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;
}
我想达到的效果是这样的:
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) }) }
};
}
但是编译器抱怨 Parameter::ParameterTypeB { s }
被部分移动并拒绝将其与 param: p
一起使用。
根据编译器的建议和提到的SO线程,我将第二个匹配更改为
Parameter::ParameterTypeB { ref s } => { Ok(Result { param: p, res: use_string(s.to_string()) }) }
但编译器再次抱怨 {ref s}
借用了 p.s
,在创建结果时无法移动。
这个问题应该怎么解决?请理解,修改函数签名或数据类型不是一种选择。
MVE 在 play.rust-lang.org 可用。
解决此问题的最惯用方法是更改 use_string
的签名,使其采用 &str
而不是 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 }) }
};
}
请注意,我已经更改了 res
和 param
的顺序,以便在实例化 Res
时 res
排在第一位。这是因为它们是从左到右求值的,首先使用 param: p
会移动 p
并且无法在后续调用中使用 s
(借用 p
)至 use_string
.
由于您声明更改签名不是一个选项,因此您需要克隆字符串,以便 p
在调用 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 }) }
};
}
问题
考虑这些类型和函数:
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;
}
我想达到的效果是这样的:
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) }) }
};
}
但是编译器抱怨 Parameter::ParameterTypeB { s }
被部分移动并拒绝将其与 param: p
一起使用。
根据编译器的建议和提到的SO线程,我将第二个匹配更改为
Parameter::ParameterTypeB { ref s } => { Ok(Result { param: p, res: use_string(s.to_string()) }) }
但编译器再次抱怨 {ref s}
借用了 p.s
,在创建结果时无法移动。
这个问题应该怎么解决?请理解,修改函数签名或数据类型不是一种选择。
MVE 在 play.rust-lang.org 可用。
解决此问题的最惯用方法是更改 use_string
的签名,使其采用 &str
而不是 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 }) }
};
}
请注意,我已经更改了 res
和 param
的顺序,以便在实例化 Res
时 res
排在第一位。这是因为它们是从左到右求值的,首先使用 param: p
会移动 p
并且无法在后续调用中使用 s
(借用 p
)至 use_string
.
由于您声明更改签名不是一个选项,因此您需要克隆字符串,以便 p
在调用 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 }) }
};
}