Error handling and iterator, map, collect


#1

Hi,

This is my basic code for parsing an IPv4 address, and I don’t like the error handling:

let ip_parts = addr_parts[0].split(".").
        map(|s| s.parse::<u8>().ok().expect("only numbers 0-255 in ip address")).
        collect::<Vec<u8>>();

How should I go about it? There doesn’t seem to be a function that collects the elements in a Vec or returns an error, i.e. collect() -> Result<Vec<_>, Err(…)>. So how would one go about this more idiomatically, without causing a panic call on a parse error?

Thanks,

Theo


#2

You can actually collect to a Result<Vec<u8>, _> and skip the .ok().expect(...) part.


#3

Now I see it. The way I read the documentation, collect() maps Result<A, B> onto Vec<Result<A, B>>, but it has another implementation for Result<>. It just need explicit typing. I’m new to Rust, and didn’t expect that.

It doesn’t work for other functions like partition() or all() as well, does it?

Thanks!


#4

It doesn’t look like Result implements Extend, so partition(...) wouldn’t work. all(...) should work, since it doesn’t matter what the items are and it doesn’t collect them in anything.


#5

I must learn to read those type definitions a bit better. There’s a lot hidden in them. I see them as in C/Java/etc, where they are just requirements on the input parameter or result. In Rust, they are used for more than that. Almost like part of the function name. Well, some rethinking to do. Thanks again.


#6

They are very similar to generics with interfaces in Java. They tell you how the type has to be, and not so much what it has be. And yes, you could say that they are a part of the function name, but it’s usually invisible, since the compiler is very good at selecting the one we want to use.


#7

The way I see it now, they are not completely like Java generics. You write List to define a list of elements of type T, but the implementation is independent of T. In the case of collect() that had me stumped, a different implementation is chosen depending on the precise type of collect(). That’s something you wouldn’t be able to do in Java. In C++ there is overloading, but not on the output type (if I’m not mistaken). It’s a bit of a different ball game, a more powerful one.


#8

It may be more powerful, but it’s still very similar. It’s not overloading, as in writing multiple implementations of collect. That’s not even possible in Rust (not as in Java, at least). What it does is that it require the output type to implement FromIterator, which has a static method that makes a new instance of the output type.


#9

Is the implementation of collect::<Result<Vec<_>, > the same as collect::<Vec<Result<, _>>?


#10

It’s all here: https://doc.rust-lang.org/nightly/src/core/iter.rs.html#1465