首页 文章

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

提问于
浏览
9

这不是一个惯用的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,找到集合:: string :: String(期望的str,找到struct collections :: string :: String)[E0308] <std macros> :3 $ crate :: result :: Result :: Ok(val)=> val,$ crate :: result :: Result :: <std macros>:1:1:6:48注意:在扩展中尝试! <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())); 没有?从我天真的角度来看,它们似乎是等价的,所以我不理解 .

1 回答

  • 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,如果块具有已知类型 .

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

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

相关问题