What can be done with Rust's generic FromStr object?

为君一笑 提交于 2020-06-23 12:55:42

问题


Rust's str class has a parse method that returns a FromStr object. parse is templated, and so the type that's being parsed from the str can be manually specified, e.g. "3".parse::<i32>() evaluates to (a Result object containing) the 32-bit int 3.

But failing to specify the type does not seem to be an error in itself. Instead, I get an error when trying to print the resulting (generic/unspecified) FromStr object:

let foo = "3".parse();
match foo
{
    Ok(m) => println!("foo: {}", m),
    Err(e) => println!("error! {}", e)
}

This does not give an error on the first line; instead, I get the following error:

<anon>:24:12: 24:13 error: unable to infer enough type information about `_`; type annotations or generic parameter binding required [E0282]
<anon>:24         Ok(m) => println!("foo: {}", m),

(Here, line 24 is the line with the Ok(m).)

So what is m here? Or is the "unable to infer enough type information" error actually due to the fact that parse in fact can't be called without a type specifier, and the compiler just doesn't catch the error until the first line where the resulting Ok type is actually used?


回答1:


Rust's str class has a parse method that returns a FromStr object.

Stop right here, this is your error.

parse does not return a FromStr object; FromStr is a trait which can be thought of as an abstract class if you come from an OO background, and you cannot return an object with an abstract type: it's abstract!

What parse does return, thus, is an instance of some type T which must implement the FromStr interface.

But failing to specify the type does not seem to be an error in itself. Instead, I get an error when trying to print the resulting (generic/unspecified) FromStr object

Because there cannot be such generic/unspecific FromStr object. A concrete type must be inferred (from context) or explicitly spelled out, and this type must implement FromStr.

So what is m here?

Only you know what it should be, the compiler does not, and thus complain that it does not know what to do :)

Or is the "unable to infer enough type information" error actually due to the fact that parse in fact can't be called without a type specifier, and the compiler just doesn't catch the error until the first line where the resulting Ok type is actually used?

Basically.

Except that it's not so much that the compiler doesn't catch the error until the first line where the resulting Ok is used, and more that the compiler considers the full function at once when inferring types. From the point of view of the compiler, whether the actual clue to infer the type comes immediately or comes 50 lines down does not matter, it only needs to be present in the current function body.

It might lead to the complaint about the lack of type originating in an odd place from the developer point of view; this is one of the downfalls of type inference. On the other hand, the compiler just cannot know where YOU would prefer to put the annotation. There are after all many possibilities:

// Example 1: immediately specifying the type
fn main() {
    let foo = "3".parse::<i32>();
    match foo
    {
        Ok(m) => println!("foo: {}", m),
        Err(e) => println!("error! {}", e)
    }
}

// Example 2: partially specifying the result type
// Note: the "_" is deduced to be std::num::ParseIntError because
//       this is how `FromStr::Err` is defined for `i32`.
fn main() {
    let foo: Result<i32, _> = "3".parse();
    match foo
    {
        Ok(m) => println!("foo: {}", m),
        Err(e) => println!("error! {}", e)
    }
}

// Example 3: specifying the result type of unwrapping
fn doit() -> Result<(), std::num::ParseIntError> {
    let foo: i32 = try!("3".parse());
    println!("foo: {}", foo);
    Ok(())
}

fn main() {
    match doit()
    {
        Ok(_) => (),
        Err(e) => println!("error! {}", e)
    }
}

// Example 4: letting the type be inferred from a function call
fn callit(f: i32) {
    println!("f: {}", f);
}

fn main() {
    let foo = "3".parse();
    match foo
    {
        Ok(m) => callit(m),
        Err(e) => println!("error! {}", e)
    }
}



回答2:


It's just not clear what m is here, as there isn't enough information to say. Is it an i32? A u64? Nobody, including Rust, can know.

You need to do something to help figure out what type it is. Either pass it to a function expecting a specific type, or annotate it such that it can be determined what type it should be.



来源:https://stackoverflow.com/questions/32687388/what-can-be-done-with-rusts-generic-fromstr-object

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!