E0308 reading lines from file with for line in reader.lines() - io

I am an experienced developer currently trying to teach myself Rust and am writing a simple program to read lines from a file. I have read the Rust std:io, std:result and other documentation forward and backwards and this code is largely taken straight from the docs. I can't understand why the following program does not compile.
use std::io;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
fn main() {
File::open("./data/test")
.map_err(|err| err.to_string())
.and_then( |mut dataFile| {
let mut reader = BufReader::new(dataFile);
for line in reader.lines() {
println!("{}",line.unwrap());
};
});
}
The compile error I am receiving when I run cargo build is
src/main.rs:10:35: 16:10 error: mismatched types:
expected `core::result::Result<_, collections::string::String>`,
found `()`
(expected enum `core::result::Result`,
found ()) [E0308]
src/main.rs:10 .and_then( |mut dataFile| {
src/main.rs:11 let mut reader = BufReader::new(dataFile);
src/main.rs:12 for line in reader.lines() {
src/main.rs:13 println!("{}",line.unwrap());
src/main.rs:14
src/main.rs:15 };
...
src/main.rs:10:35: 16:10 help: run `rustc --explain E0308` to see a detailed explanation
error: aborting due to previous error
I am running Rust 1.4.0.

You shouldn't be using and_then, but map.
Correct code:
File::open("./data/test")
.map_err(|err| err.to_string())
.map(|mut dataFile| {
let mut reader = BufReader::new(dataFile);
for line in reader.lines() {
println!("{}",line.unwrap());
};
});
You can see it in both functions signatures:
fn and_then<U, F: FnOnce(T) -> Result<U, E>>(self, op: F) -> Result<U, E>
fn map<U, F: FnOnce(T) -> U>(self, op: F) -> Result<U, E>
The key difference here is that the operation op must return something wrapped in a Result in and_then's case, whereas it doesn't have to be wrapped in map's case. Your closure doesn't return anything, so in Rust's view it actually returns (), and () cannot match Result<U, E>. However () can match U, which is why the second signature works.

As mdup explains, map and and_then are used to transform a Result with a closure. map is used when you want to change the inner type, and_then is used when you want to chain a second thing that results in another Result without nesting them.
However, neither of these is idiomatic for your case as you are not transforming the value. Instead, you want a match or if let statement. These are more appropriate for side effects.
Additionally, Rust uses snake_case identifiers, and you don't need to have any of the variables be marked as mutable. These are all compiler warnings you would see once it compiles.
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
fn main() {
let f = File::open("./data/test")
.map_err(|err| err.to_string());
if let Ok(data_file) = f {
let reader = BufReader::new(data_file);
for line in reader.lines() {
println!("{}", line.unwrap());
};
}
}

Related

What is the difference between the ? operator and returning Err(e)? [duplicate]

I'm reading the documentation for File:
//..
let mut file = File::create("foo.txt")?;
//..
What is the ? in this line? I do not recall seeing it in the Rust Book before.
As you may have noticed, Rust does not have exceptions. It has panics, but their use for error-handling is discouraged (they are meant for unrecoverable errors).
In Rust, error handling uses Result. A typical example would be:
fn halves_if_even(i: i32) -> Result<i32, Error> {
if i % 2 == 0 {
Ok(i / 2)
} else {
Err(/* something */)
}
}
fn do_the_thing(i: i32) -> Result<i32, Error> {
let i = match halves_if_even(i) {
Ok(i) => i,
Err(e) => return Err(e),
};
// use `i`
}
This is great because:
when writing the code you cannot accidentally forget to deal with the error,
when reading the code you can immediately see that there is a potential for error right here.
It's less than ideal, however, in that it is very verbose. This is where the question mark operator ? comes in.
The above can be rewritten as:
fn do_the_thing(i: i32) -> Result<i32, Error> {
let i = halves_if_even(i)?;
// use `i`
}
which is much more concise.
What ? does here is equivalent to the match statement above with an addition. In short:
It unpacks the Result if OK
It returns the error if not, calling From::from on the error value to potentially convert it to another type.
It's a bit magic, but error handling needs some magic to cut down the boilerplate, and unlike exceptions it is immediately visible which function calls may or may not error out: those that are adorned with ?.
One example of the magic is that this also works for Option:
// Assume
// fn halves_if_even(i: i32) -> Option<i32>
fn do_the_thing(i: i32) -> Option<i32> {
let i = halves_if_even(i)?;
// use `i`
}
The ? operator, stabilized in Rust version 1.13.0 is powered by the (unstable) Try trait.
See also:
Is the question mark operator ? equivalent to the try! macro?
Why do try!() and ? not compile when used in a function that doesn't return Option or Result?
It is a postfix operator that unwraps Result<T, E> and Option<T> values.
If applied to Result<T, E>, it unwraps the result and gives you the inner value, propagating the error to the calling function.
let number = "42".parse::<i32>()?;
println!("{:?}", number); // 42
When applied to an Option<T>, it propagates None to the caller, leaving you the content of the Some branch to deal with.
let val = Some(42)?;
println!("{:?}", val); // 42
The ? operator can only be used in a function that returns Result or Option like so:
use std::num::ParseIntError;
fn main() -> Result<(), ParseIntError> {
let number = "42".parse::<i32>()?;
println!("{:?}", number);
Ok(())
}
It is a convenience offered by Rust, that eliminates boilerplate code and makes function's implementation simpler.
It is used for propagating errors. Sometimes we write code that might fail but we do not want to catch and handle error immediately. Your code will not be readable if you have too much code to handle the error in every place. Instead, if an error occurs, we might want to let our caller deal with it. We want errors to propagate up the call stack.
// file type is Result if "?" is not used
// file:Result<File,Error>
let mut file = File::create("foo.txt");
// file type is File if "?" is used
// file:File
let mut file = File::create("foo.txt")?;
// if an error occurs, code after this line will not be executed
// function will return the error
The behavior of ? depends on whether this function returns a successful result or an error result:
If it is a success, it unwraps the Result to get the success value inside. Value is assigned to the variable file
If the result is an error, the error is NOT assigned to the variable file. Error is returned by the function to the caller
Using ? same as this code
let mut file = match File::create("foo.txt") {
Err(why) => panic!("couldn't create {}: {}", display, why),
Ok(file) => file,
};
? also works similarly with the Option type. In a function that returns Option, you
can use ? to unwrap a value and return early in the case of None :
The existing answers are all great! I would like to give a small code snippet to demo the use of From::from() behand this question mark:
fn _parse(str: &str) -> Result<i32, &str> {
if let Ok(num) = str.parse::<i32>() {
Ok(num)
} else {
Err(str)
}
}
fn parse(str: &str) -> Result<(), String> {
let num = _parse(str)?;
println!("{}", num);
Ok(())
}
The use of ? in function parse() can be manually rewritten as:
fn parse(str: &str) -> Result<(), String> {
match _parse(str) {
Ok(n) => {
println!("{}", n);
Ok(())
}
Err(str) => Err(<String as From<&str>>::from(str)),
}
}

What's the recommended way to produce side effects in control flow using Result?

Result::and_then() works great for composing control flow.
fn some_fn() -> Result<String, Error> {
Ok("Yay".to_string())
}
some_fn()
.and_then(|value| some_other_fn())
.and_then(|some_other_value| /* ... */)
Sometimes we want to create a side effect and still propagate the emitted value. Let's say we want to print the value the moment we receive it:
some_fn()
.and_then(|value| {
println!("{}", &value);
some_other_fn()
})
.and_then(|some_other_value| /* ... */)
Is there a better way to do this? Something like Reactive Extensions' tap() operator would be great.
map and and_then are appropriate for when you want to transform the value. Using match or if let is appropriate for side effects:
let r = some_fn();
if let Ok(v) = &r {
println!("{}", v);
}
r.and_then(|_| some_other_fn())
See also:
Why does Rust need the `if let` syntax?
Assuming that you only care about side effects when the Result is Ok...
You could also create an extension trait to add the desired method to Result. I'd advocate for calling it inspect as that's the name of the parallel method on Iterator.
trait InspectExt<T> {
fn inspect<F>(self, f: F) -> Self
where
F: FnOnce(&T);
}
impl<T, E> InspectExt<T> for Result<T, E> {
fn inspect<F>(self, f: F) -> Self
where
F: FnOnce(&T),
{
if let Ok(v) = &self {
f(v)
}
self
}
}
some_fn()
.inspect(|v| println!("{}", v))
.and_then(|_| some_fn())
See also:
Is there a way other than traits to add methods to a type I don't own?

Why can't I use the ? operator in my main function on a function that returns an Option?

Using this file:
use std::env;
fn main() {
println!("{}", env::args().nth(3)?);
}
I get this error:
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
--> src/main.rs:4:20
|
4 | println!("{}", env::args().nth(3)?);
| ^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
|
= help: the trait `std::ops::Try` is not implemented for `()`
= note: required by `std::ops::Try::from_error`
However this is confusing because nth does return Option:
fn nth(&mut self, n: usize) -> Option<Self::Item>
Am I misunderstanding the documentation or is this a bug?
The return type of main must implement std::process::Termination(currently it's an unstable trait). If you look at the end of the documentation, you will see:
impl Termination for !
impl Termination for ()
impl Termination for ExitCode
impl<E: Debug> Termination for Result<!, E>
impl<E: Debug> Termination for Result<(), E>
If you want to return an Option you must implement the trait on it. This is not practical because you can't implement a trait on foreign type, so the best solution is to convert Option<T> to Result<T, E>:
use std::env;
fn main() -> Result<(), Box<std::error::Error>> {
println!("{}", env::args().nth(3).ok_or("Missing argument")?);
Ok(())
}
See also:
Why do try!() and ? not compile when used in a function that doesn't return Option or Result?
The ? operator will cause the function containing it to return None if the value the ? is applied to is None.
This means you can write
fn not_main() -> Option<()> {
println!("{}", std::env::args().nth(3)?);
Ok(())
}
since nth returns an Option<Item> and not_main returns an Option<()>.
However, your main does not return an Option, hence ? can't work inside it.
How you work around this will depend on what you want to do in the case of a missing argument. The most brutal solution is to unwrap instead - which will cause your code to panic.
fn main() {
println!("{}", env::args().nth(3).unwrap())
}
An alternative is to match and handle the missing case
fn main() {
match std::env::args().nth(3) {
Some(ref v) => println!("{}", v),
None => println!("Missing argument"),
}
}
Since Option supports Debug you could print the debug version - which will output None, or Some("arg3").
fn main() {
println!("{:?}", std::env::args().nth(3));
}
If you really want to use ? on a Option value in main, you probably need to implement you own Option.
In your case, nothing::Probably is a better Option.
Example (you need nightly toolchain to run it):
use nothing::{Nothing, Probably, Something};
fn get_args() -> Probably<Vec<String>> {
match std::env::args().skip(1).collect::<Vec<String>>() {
args # _ if args.len() > 0 => Something(args),
_ => Nothing,
}
}
fn main() -> Probably<Vec<String>> {
let some_args = get_args();
println!("some_args = {some_args:?}");
let args = some_args?; // <- it returns here if some_args is Nothing
println!("args = {args:?}");
Something(args)
}
It works because Probably implements std::process::Termination so you can return it from you main function. Additionally it implements std::ops::Try so you can use ? on it.

What is this question mark operator about?

I'm reading the documentation for File:
//..
let mut file = File::create("foo.txt")?;
//..
What is the ? in this line? I do not recall seeing it in the Rust Book before.
As you may have noticed, Rust does not have exceptions. It has panics, but their use for error-handling is discouraged (they are meant for unrecoverable errors).
In Rust, error handling uses Result. A typical example would be:
fn halves_if_even(i: i32) -> Result<i32, Error> {
if i % 2 == 0 {
Ok(i / 2)
} else {
Err(/* something */)
}
}
fn do_the_thing(i: i32) -> Result<i32, Error> {
let i = match halves_if_even(i) {
Ok(i) => i,
Err(e) => return Err(e),
};
// use `i`
}
This is great because:
when writing the code you cannot accidentally forget to deal with the error,
when reading the code you can immediately see that there is a potential for error right here.
It's less than ideal, however, in that it is very verbose. This is where the question mark operator ? comes in.
The above can be rewritten as:
fn do_the_thing(i: i32) -> Result<i32, Error> {
let i = halves_if_even(i)?;
// use `i`
}
which is much more concise.
What ? does here is equivalent to the match statement above with an addition. In short:
It unpacks the Result if OK
It returns the error if not, calling From::from on the error value to potentially convert it to another type.
It's a bit magic, but error handling needs some magic to cut down the boilerplate, and unlike exceptions it is immediately visible which function calls may or may not error out: those that are adorned with ?.
One example of the magic is that this also works for Option:
// Assume
// fn halves_if_even(i: i32) -> Option<i32>
fn do_the_thing(i: i32) -> Option<i32> {
let i = halves_if_even(i)?;
// use `i`
}
The ? operator, stabilized in Rust version 1.13.0 is powered by the (unstable) Try trait.
See also:
Is the question mark operator ? equivalent to the try! macro?
Why do try!() and ? not compile when used in a function that doesn't return Option or Result?
It is a postfix operator that unwraps Result<T, E> and Option<T> values.
If applied to Result<T, E>, it unwraps the result and gives you the inner value, propagating the error to the calling function.
let number = "42".parse::<i32>()?;
println!("{:?}", number); // 42
When applied to an Option<T>, it propagates None to the caller, leaving you the content of the Some branch to deal with.
let val = Some(42)?;
println!("{:?}", val); // 42
The ? operator can only be used in a function that returns Result or Option like so:
use std::num::ParseIntError;
fn main() -> Result<(), ParseIntError> {
let number = "42".parse::<i32>()?;
println!("{:?}", number);
Ok(())
}
It is a convenience offered by Rust, that eliminates boilerplate code and makes function's implementation simpler.
It is used for propagating errors. Sometimes we write code that might fail but we do not want to catch and handle error immediately. Your code will not be readable if you have too much code to handle the error in every place. Instead, if an error occurs, we might want to let our caller deal with it. We want errors to propagate up the call stack.
// file type is Result if "?" is not used
// file:Result<File,Error>
let mut file = File::create("foo.txt");
// file type is File if "?" is used
// file:File
let mut file = File::create("foo.txt")?;
// if an error occurs, code after this line will not be executed
// function will return the error
The behavior of ? depends on whether this function returns a successful result or an error result:
If it is a success, it unwraps the Result to get the success value inside. Value is assigned to the variable file
If the result is an error, the error is NOT assigned to the variable file. Error is returned by the function to the caller
Using ? same as this code
let mut file = match File::create("foo.txt") {
Err(why) => panic!("couldn't create {}: {}", display, why),
Ok(file) => file,
};
? also works similarly with the Option type. In a function that returns Option, you
can use ? to unwrap a value and return early in the case of None :
The existing answers are all great! I would like to give a small code snippet to demo the use of From::from() behand this question mark:
fn _parse(str: &str) -> Result<i32, &str> {
if let Ok(num) = str.parse::<i32>() {
Ok(num)
} else {
Err(str)
}
}
fn parse(str: &str) -> Result<(), String> {
let num = _parse(str)?;
println!("{}", num);
Ok(())
}
The use of ? in function parse() can be manually rewritten as:
fn parse(str: &str) -> Result<(), String> {
match _parse(str) {
Ok(n) => {
println!("{}", n);
Ok(())
}
Err(str) => Err(<String as From<&str>>::from(str)),
}
}

Can't figure out return type of this Rust function that returns Iter?

I have this small Rust function:
pub fn factor(input_array: &mut [i32]) {
let x = input_array
.iter()
.filter(|&x| x % 2 == 0);
x
}
When I run this via cargo run I get this error:
Compiling gettingrusty v0.0.1 (file:///home/lowks/src/rust/gettingrusty)
src/functional.rs:22:9: 22:10 error: mismatched types:
expected `()`,
found `core::iter::Filter<core::slice::Iter<'_, i32>, [closure#src/functional.rs:21:21: 21:36]>`
(expected (),
found struct `core::iter::Filter`) [E0308]
src/functional.rs:22 x
^
src/functional.rs:22:9: 22:10 help: run `rustc --explain E0308` to see a detailed explanation
error: aborting due to previous error
Could not compile `gettingrusty`.
I tried a few return types such as slice::Iter<i32> and core::slice::Iter<i32> but seems like all of them are wrong. What should be the return type of my function?
Under normal circumstances, you could just copy+paste the found part of the error message. There are two problems with that in this particular case.
First, core isn't directly accessible. Various items are exposed by the standard library libstd, but are actually defined by libcore. Basically, the standard library is the public interface you are meant to use to access these items, but the compiler doesn't know that. Typically, you work around this by just replacing core::* with std::*.
The second problem is that the type includes a closure, and closures cannot be named. The simplest solution is to just not use a closure at all; you aren't capturing anything, anyway.
Doing that and just fixing the compile errors as they come up leads to:
pub fn factor(input_array: &mut [i32])
-> std::iter::Filter<std::slice::Iter<i32>, fn(&&i32) -> bool> {
fn even(x: &&i32) -> bool { **x % 2 == 0 }
let x = input_array
.iter()
.filter(even as for<'r> fn(&'r &_) -> _);
x
}
Your function returns a Filter object, so its actual return type is Filter<_, _> for some generic arguments. That’s fine, but chances are, you’ll want to hide all the implementation details from the type signature and just say that your function returns some iterator. Unfortunately, there is no (as of today) easy way to do this.
The pattern that seems to be rather common is to use a newtype wrapper. The problem with this is that writing the wrapper is a little bit more difficult than one might expect, e.g. one will have to deal with lifetimes explicitly.
Here is a complete example:
use std::iter::Filter;
use std::slice::Iter;
struct FactorResult<'a, T: 'a>(Filter<Iter<'a, T>, fn(&&T) -> bool>);
impl<'a, T> Iterator for FactorResult<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<&'a T> { self.0.next() }
fn size_hint(&self) -> (usize, Option<usize>) { self.0.size_hint() }
}
fn factor(input_array: &[i32]) -> FactorResult<i32> {
fn even(x : &&i32) -> bool { **x % 2 == 0 }
FactorResult(input_array.iter().filter(even))
}
fn main () {
for x in factor(&[1,2,3,4]) {
println!("{}", x);
}
}
The factor function returns a FactorResult which is just a wrapper that hides the actual underlying type.
The only thing the user knows about FactorResult is that it is an Iterator. The implementation of the trait is trivial, but I had to spell it out.
I had to replace the closure with the function. This is because here Rust does not perform any allocations, so it needs to know the size of FactorResult<T>, but the type of the closure is anonymous so there is no way to refer to it. One could use a closure but the whole thing would have to be boxed in this case.

Resources