这不是一个惯用的MVCE,但它应该说明这个问题。给出以下代码:
fn foo() -> Result<String, i32> {
return Ok("world".to_string());
}
fn bar() -> Result<String, i32> {
let mut value = String::new();
value.push_str(&try!(foo())); // this line here
return Ok("Hello ".to_string() + &value);
}
fn main() {
match bar() {
Ok(message) => println!("{}", message),
_ => return,
}
}
Rust返回错误:
<std macros>:3:43: 3:46
错误:类型不匹配:
预期str
,
找到collections::string::String
(预期str
,
找到了结构collections::string::String
)[E0308]
<std macros>:3 $ crate:: result:: Result:: Ok ( val ) => val , $ crate:: result:: Result::
<std macros>:1:1: 6:48
注意:扩展try!
<std macros>:3:43: 3:46
帮助:运行rustc --explain E0308
以查看详细说明 错误:由于先前的错误导致中止
如果我改为捕获try!
的结果并单独将&
应用于结果,则它可以正常工作(并打印出Hello world
):
fn foo() -> Result<String, i32> {
return Ok("world".to_string());
}
fn bar() -> Result<String, i32> {
let mut value = String::new();
let foo_result = try!(foo()); // capture the result of try!
value.push_str(&foo_result); // now use the result with &
return Ok("Hello ".to_string() + &value);
}
fn main() {
match bar() {
Ok(message) => println!("{}", message),
_ => return,
}
}
为什么let foo_result = try!(foo()); value.push_str(&foo_result);
有效但value.push_str(&try!(foo()));
没有?从我天真的角度来看,它们似乎是等价的,所以我不确定Rust的哪个关键部分我不理解。
答案 0 :(得分:12)
似乎编译器以不同方式处理块的强制。 try!()
被扩展为match
块,编译器无法自动解除它。您的问题可以缩写如下:
fn f(_: &str) {}
fn main() {
let x = "Akemi Homura".to_owned();
f(&x); // OK
f(&(x)); // OK
f(&{x}); // Error
}
我认为这是编译器的错误。如RFC 401中所述,编译器应该能够强制使用适当类型的块。
块,如果块具有类型
U
,则块中的最后一个表达式(如果它) 不是以分号终止的)是U
的强制网站。这包括块 它们是控制流语句的一部分,例如if
/else
,如果是块 有一个已知的类型。
作为解决方法,我建议您使用String
或&str
直接将&*try()
转换为&try()[..]
。两者都有相同的含义,虽然我稍微偏爱前者。
我打开了一个问题来跟踪这个问题。 https://github.com/rust-lang/rust/issues/26978