为什么我不能参考试试的结果!用&?

Cor*_*lks 9 rust

这不是一个惯用的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,
    }
}
Run Code Online (Sandbox Code Playgroud)

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,
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么let foo_result = try!(foo()); value.push_str(&foo_result);工作但value.push_str(&try!(foo()));不是?从我天真的角度来看,它们似乎是等价的,所以我不确定Rust的哪个关键部分我不理解.

Bar*_*Lee 12

似乎编译器以不同方式处理块的强制.try!()被扩展为match块,编译器无法自动解除它.您的问题可以缩写如下:

fn f(_: &str) {}

fn main() {
    let x = "Akemi Homura".to_owned();

    f(&x); // OK
    f(&(x)); // OK
    f(&{x}); // Error
}
Run Code Online (Sandbox Code Playgroud)

我认为这是编译器的一个错误.如RFC 401中所述,编译器应该能够使用适当的类型强制阻塞块.

块,如果一个块有类型U,那么块中的最后一个表达式(如果它不是以分号结尾)是一个强制站点U.这包括作为控制流语句的一部分的块,例如if/ else,如果块具有已知类型.

作为一种解决方法,我建议您直接转换String&str使用&*try()&try()[..].两者都有相同的含义,虽然我更喜欢前者.

我打开了一个问题来跟踪这一点.https://github.com/rust-lang/rust/issues/26978