2015-07-11 7 views
9

Es ist nicht gerade eine idiomatische MVCE, aber es sollte die Frage veranschaulichen. Angesichts der folgenden Code:Warum kann ich nicht die Referenz des Versuchsergebnisses nehmen! mit &?

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 den Fehler zurückgibt:

<std macros>:3:43: 3:46 error: mismatched types:
expected str ,
found collections::string::String
(expected str ,
found struct collections::string::String) [E0308]
<std macros>:3 $ crate:: result:: Result:: Ok (val) => val , $ crate:: result:: Result::
<std macros>:1:1: 6:48 note: in expansion of try!
<std macros>:3:43: 3:46 help: run rustc --explain E0308 to see a detailed explanation
error: aborting due to previous error

Wenn ich stattdessen das Ergebnis try! erfassen und separat & auf das Ergebnis anwenden, es funktioniert (und druckt 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, 
    } 
} 

Warum funktioniert let foo_result = try!(foo()); value.push_str(&foo_result); funktioniert aber value.push_str(&try!(foo())); nicht? Aus meiner naiven Perspektive scheinen sie gleichwertig zu sein, also bin ich mir nicht sicher, welchen Schlüsselabschnitt von Rust ich nicht verstehe.

+0

Es ist eine sehr gute MVCE. Keine Antwort, aber immer noch ein bisschen was ich normalerweise tue: http://is.gd/PZKWz0 – ArtemGr

+0

Sie können sogar mit value.push_str (&& try! (Foo())) auflösen; – eulerdisk

+0

Danke, @Shpmaster. Du hast vollkommen recht. – Cornstalks

Antwort

12

Es scheint, dass der Compiler die Nötigung eines Blocks anders handhabt. try!() wird zu einem match Block erweitert, und der Compiler kann es nicht automatisch derefrieren. Ihr Problem kann wie folgt abgekürzt werden:

fn f(_: &str) {} 

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

    f(&x); // OK 
    f(&(x)); // OK 
    f(&{x}); // Error 
} 

Ich denke, das ist ein Fehler des Compilers. Wie in RFC 401 angegeben, sollte der Compiler Blöcke mit geeigneten Typen erzwingen können.

blocks, if a block has type U , then the last expression in the block (if it is not semicolon-terminated) is a coercion site to U . This includes blocks which are part of control flow statements, such as if/else , if the block has a known type.

Als Abhilfe können, empfehle ich Ihnen String in &str direkt zu konvertieren, &*try() oder &try()[..] verwenden. Beide haben die gleiche Bedeutung, obwohl ich ersteres etwas bevorzuge.

Ich habe ein Problem geöffnet, um dies zu verfolgen. https://github.com/rust-lang/rust/issues/26978

Verwandte Themen