I am trying to get a subset of a Lines object. Ideally between indices a and b, but for now I'm just trying to get the first n lines.
I have tried slicing, using take and iterating using a loop, but it seems that Lines isn't the same as a normal iterator. See the following MWE with some of my attempts:
use std::env;
use std::fs;
use std::str::Lines;
fn main() {
let args: Vec<String> = env::args().collect();
let filename = &args[1];
let contents = fs::read_to_string(filename).expect("Something went wrong reading the file");
let contents_lines = contents.lines();
println!("{:?}", dummy_function1(contents_lines, 5));
println!("{:?}", dummy_function2(contents_lines, 5));
println!("{:?}", dummy_function3(contents_lines, 5));
}
fn dummy_function1(lines: Lines, n: usize) {
return lines[..n];
}
fn dummy_function2(lines: Lines, n: usize) {
return lines.take(n);
}
fn dummy_function3(lines: Lines, n: usize) {
let output = Vec::new();
for (i, l) in lines.enumerate() {
if i < n {
output.push(l);
} else {
break;
}
}
return;
}
Ah, thank you! I didn't realise that I needed to make the return type explicit because my linter wasn't complaining about it, I should have read the documentation better
use std::env;
use std::fs;
use std::str::Lines;
fn main() {
let args: Vec<String> = env::args().collect();
let filename = &args[1];
let contents = fs::read_to_string(filename).expect("Something went wrong reading the file");
let contents_lines = contents.lines();
//println!("{:?}", dummy_function1(contents_lines, 5));
// the debug printout of this one is not particularly nice,
// but using it as an iterator should works:
println!("{:?}", dummy_function2(contents_lines, 5));
// don’t re-use the same `Lines` iterator:
let contents_lines = contents.lines();
println!("{:?}", dummy_function3(contents_lines, 5));
}
/* this can’t work
fn dummy_function1(lines: Lines, n: usize) {
return lines[..n];
}
*/
use std::iter;
// was missing return type
fn dummy_function2(lines: Lines<'_>, n: usize) -> iter::Take<Lines<'_>> {
return lines.take(n);
}
// was missing return type
fn dummy_function3(lines: Lines<'_>, n: usize) -> Vec<&str> {
let mut output = Vec::new();
for (i, l) in lines.enumerate() {
if i < n {
output.push(l);
} else {
break;
}
}
return output;
}
Rust intentionally doesn't provide global type inference. Function items and methods always need to declare argument and return types explicitly. Inferring either of these only works for closures.
Also consider not using an explicit return at the end of your functions. Rust is an expression-based language – the last expression of a block is its value, and this also applies to functions (as well as other block-bodied expressions, like if…else and match).
Returning a Vec should be avoided if you don’t need it, e.g. when all you need to do is iterate over the resulting iterator, since it involves additional allocation.