Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic function to parse numbers fails with "FromStr is not implemented"

Tags:

generics

rust

I have this generic function in my Rust code:

fn test<T>(text: &str) -> T {
    text.parse::<T>()
}

The idea is that the caller would do something like

test::<u64>("2313");

But the compilation fails with this message

error: the trait `core::str::FromStr` is not implemented for the type `T` [E0277]

I just started learning Rust yesterday, so this is probably a very basic question that I've failed to find the answer to.

like image 636
Sassa Avatar asked Oct 26 '25 22:10

Sassa


2 Answers

Like the error message states, T needs to implement core::str::FromStr in order to be applicable for the parse function. The type signature of parse is:

fn parse<F>(&self) -> Result<F, F::Err> where F: FromStr

Which limits the sort of F (or, in your case T) you can use to those implementing FromStr. Your other problem is the type returned by test; it should be the same as the one of parse - a Result.

When you fix those issues, your function will work:

use std::str::FromStr;

fn test<T: FromStr>(text: &str) -> Result<T, T::Err> {
    text.parse::<T>()
}

fn main() {
    println!("{:?}", test::<u64>("2313"));
}

Ok(2313)

like image 89
ljedrz Avatar answered Oct 29 '25 11:10

ljedrz


When you declare a generic type parameter T, you don't know anything about that type. It could be i32, String, () or PinkElephant; only two of those can be parsed from a string.

The way to restrict types in Rust is by trait bounds: we explicitly request a specific behavior from the type. Like "this type can be any type but I at least want the possibility to clone one instance of this type" (this would be the Clone trait). You can (and should!) read more about the topic of traits in the dedicated chapter in the Rust book.

So what feature do you expect from your type T? You want to create an instance of T from a string by using str::parse(). The function signature of parse() is:

fn parse<F>(&self) -> Result<F, F::Err> 
    where F: FromStr

It also takes this generic parameter F and bounds it with the trait FromStr. Thus, in order to use parse(), your type parameter T also needs to implement FromStr. Your function could look like this:

use std::str::FromStr;

fn test<T: FromStr>(text: &str) -> T {
    text.parse::<T>().expect("string was invalid!")
}

What is this expect() you ask? Well... we are touching another topic here: error handling. There is also a chapter on that topic in the book, which you should read. In short: you need to somehow handle the case that the string was invalid (like "peter" when you were trying to parse an integer). expect() is probably the wrong way here: it just panics (aborts the thread) when the parsing did not succeed.

Also remember that there is a compiler error index, in which you can read more about a specific error. Here is the entry for your error E0277.

like image 25
Lukas Kalbertodt Avatar answered Oct 29 '25 11:10

Lukas Kalbertodt