Text file manipulation (io, fs,...)


#21

Sorry, my example was incorrect. You can prefix the string with b to get a byte string (b"Hello, world!") or use .as_bytes() to convert a string slice to bytes.


#22

Cool, thank you. That worked perfectly.

Anyway, I’m also trying to wrap my head around the proper way to be using try! if not in main(). try! is all over the Rust API reference examples for File, but I’m never able to get any of them to work.

I’m using SublimeLinter-rustc, so I’m already getting errors as soon as I type:

use std::fs::File;
use std::io::prelude::*;

fn main() {
    let mut f = try!(File::open("foo.txt"));
}

That tells me Error: mismatched types: line 5 column 12. (Which, for the record, is the t in mut. Removing mut changes this to line 5 column 11, which is now the = sign. Lengthening the variable name to something like fffff throws the error at column 13. What are computers I don’t even)

Same thing happens with this:

fn main() {
    let mut f = readFile();
}

fn readFile() -> File{
    let mut f = try!(File::open("foo.txt"));
    f
}

This, on the other hand, works fine:

use std::fs::File;
use std::io::prelude::*;

fn main() {
    let mut f = File::open("foo.txt").unwrap();
    let mut s = String::new();
    f.read_to_string(&mut s);
    println!("{}", s);
}

But I’d certainly like to know how to properly use try! since the examples are all telling me to do that, so it feels like I’m doing something wrong.


#23

see the reply of @stebalien

Yes. More specifically, try! doesn’t have a return type, it contains a return statement. try! expands to:

match $expr {
Ok(v) => v,
Err(e) => return Err(::std::convert::From::from(e)) // Implicitly convert the error
}

macro is done at compile time. you have to make sure the expression after return in the macro is the same type as the fn you use it.


#24

If you click the link to run them, you’ll see that they have an implicit wrapping function that’s hidden in the Rustdoc output. This is a tradeoff we made: You can show the examples with those functions, but it’s a lot of noise. Or you can show them without it, and it’s not.

So for example: http://doc.rust-lang.org/nightly/std/fs/struct.File.html

links to http://is.gd/IbLHhd

Which has

fn foo() -> std::io::Result<()> {

If you were returning the File, that’d be std::io::Result<File> instead.


#25

Awesome. So this works:

fn main() {
    fn foo() -> std::io::Result<()>{
        let mut f = try!(File::open("foo.txt"));
        let mut s = String::new();
        try!(f.read_to_string(&mut s));
        println!("{}",s);
        Ok(())
    }
    foo();
}

But with a warning that foo() is an unused result which must be used.

So I figure I’d want to turn foo() into a function that returns a String, right? The problem is:

fn main() {
    fn foo() -> String{
        let mut f = try!(File::open("foo.txt"));
        let mut s = String::new();
        try!(f.read_to_string(&mut s));
        s
    }
    println!("{}",foo());
}

gives me a mismatched type error: expectedcollections::string::String, foundcore::result::Result<_, _>``

That’s probably related to the try! macros? So this works:

fn main() {
    fn foo() -> String{
        fn bar(mut s:&mut String) -> std::io::Result<()>{
            let mut f = try!(File::open("foo.txt"));
            try!(f.read_to_string(s));
            Ok(())
        }
        let mut s = String::new();
        bar(&mut s);
        s
    }
    println!("{}",foo());
}

but now I’m just back where I started where bar is an unused result. How can I pass its Ok result to something so that the compiler stops warning me?


#26

No. You’re getting that because Result is flagged as must_use; that is, it’s considered extremely suspicious if you ever get a Result from a function that you do not then actually use in some fashion.

What you’re doing is effectively similar to suppressing exceptions in other languages: you’re ignoring all possible errors!

You want to either explicitly throw away potential errors:

// Storing the Result counts as using it.  The variable is
// named `_` because any identifier starting with `_` won't
// be flagged as "unused".
let _ = foo();

…or do something to allow the error to surface:

// `unwrap` will extract the `Ok` value, or panic if it's an
// `Err`.
foo().unwrap();