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

时间:2015-07-11 20:08:52

标签: 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,
    }
}

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的哪个关键部分我不理解。

1 个答案:

答案 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