Using Map as an Iterator interchangeably with Vector iterator - rust

A simple program, what I am trying to do is get lines from a file, or if the file is not present, pass in a zero-length iterator:
use std::fs::File;
use std::io::{self, BufRead};
fn run_against_input(inp: &mut dyn Iterator<Item = String>) {
for i in inp {
println!("Input line: {}", i);
}
}
fn main() {
let file = File::open("data.txt");
let input: dyn Iterator<Item = String> = match file {
Ok(f) => io::BufReader::new(f).lines()
.map(|line| line.unwrap()),
Err(_) => Vec::new().into_iter()
};
run_against_input(&mut dyn input);
}
When I do this, I get the following error:
Compiling playground v0.0.1 (/playground)
error: expected expression, found keyword `dyn`
--> src/main.rs:19:28
|
19 | run_against_input(&mut dyn input);
| ^^^ expected expression
error[E0308]: mismatched types
--> src/main.rs:13:18
|
13 | Ok(f) => io::BufReader::new(f).lines()
| __________________^
14 | | .map(|line| line.unwrap()),
| |______________________________________^ expected trait object `dyn Iterator`, found struct `Map`
|
= note: expected trait object `dyn Iterator<Item = String>`
found struct `Map<std::io::Lines<BufReader<File>>, [closure#src/main.rs:14:18: 14:38]>`
For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to 2 previous errors
I do specifically need a &mut reference to the Iterator in the code I am writing (this is a small reproduction of the problem that I am facing), but I guess that has nothing to do with the issue at hand. I see that there is an impl on Iterator for Map, but the error I get is that this is not the trait object for Iterator<Item = String>. I also tried this:
let input: &mut dyn Iterator<Item = String> = match file {
Ok(f) => &mut io::BufReader::new(f).lines()
.map(|line| line.unwrap()),
Err(_) => &mut Vec::new().into_iter()
};
which of course didn't work, since the temporary value is being dropped in the statement to which I am returning a reference (which is why I did the let binding thing as the compiler suggested).
EDIT Link to playground - https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=99b8105ecc266e03db2d92cc22610962

You can hold the iterators for each branch in a separate variable outside the match (and also use std::iter::empty() instead of Vec::new().into_iter()):
use std::fs::File;
use std::io::{self, BufRead};
use std::iter;
fn run_against_input(inp: impl Iterator<Item = String>) {
for i in inp {
println!("Input line: {}", i);
}
}
fn main() {
let file = File::open("data.txt");
let mut lines;
let mut no_lines;
let input: &mut dyn Iterator<Item = String> = match file {
Ok(f) => {
lines = io::BufReader::new(f).lines().map(Result::unwrap);
&mut lines
},
Err(_) => {
no_lines = iter::empty();
&mut no_lines
},
};
run_against_input(input);
}

You can use a Box instead of a reference, so the value is owned and won't be dropped:
let mut input: Box<dyn Iterator<Item = String>> = match file {
Ok(f) => Box::new(io::BufReader::new(f).lines().map(|line| line.unwrap())),
Err(_) => Box::new(Vec::new().into_iter()),
};
playground
If you prefer you could also change your function to take a Box instead of a reference:
fn run_against_input(inp: Box<dyn Iterator<Item = String>>) {

Related

Rust Generic Function Attempt for Async Reads

My goal is to reduce the following read_stream_***() functions into a generic fuction that can be passed different streams.
use async_std::net::TcpStream;
use async_std::{ task };
use async_std::io::{ stdin, BufReader, Stdin };
use async_std:: { prelude::* };
use futures::{select, FutureExt, AsyncRead };
pub async fn read_stream_stdin(streem:Stdin) -> Result<(), std::io::Error>
{
let mut lines_from_stream = BufReader::new(streem).lines().fuse();
loop {
select! {
line = lines_from_stream.next().fuse() => match line {
Some(line) => {
println!("{:?}",line?);
}
None => break,
}
}
}
Ok(())
}
pub async fn read_stream_tcp(streem:TcpStream) -> Result<(), std::io::Error>
{
let mut lines_from_stream = BufReader::new(streem).lines().fuse();
loop {
select! {
line = lines_from_stream.next().fuse() => match line {
Some(line) => {
println!("{:?}",line?);
}
None => break,
}
}
}
Ok(())
}
pub async fn connect_tcp_server(host_port:&str) -> Result<(), std::io::Error>
{
let streem = TcpStream::connect(host_port).await;
let _result = task::block_on(read_stream_tcp(streem?));
Ok(())
}
fn main() -> Result<(), std::io::Error> {
task::spawn( connect_tcp_server("127.0.0.1:8081") );
task::block_on(read_stream_stdin(stdin()))
}
The Generic Attempt:
pub async fn read_stream<T>(streem:T) -> Result<(), std::io::Error>
{
let mut lines_from_stream = BufReader::new(streem).lines().fuse();
loop {
select! {
line = lines_from_stream.next().fuse() => match line {
Some(line) => {
println!("{:?}",line?);
}
None => break,
}
}
}
Ok(())
}
The Cargo.toml
[package]
name = "gen_func"
version = "0.1.0"
edition = "2021"
[dependencies]
async-std = "1.9.0"
futures = "0.3.21"
I attempted <T: async_std::io::Read> but fuse() and lines() are not implemented. and AsyncRead is not found in async_std::io . I found AsyncRead in futures crate but again fuse() and lines() were not implemented. I am not set on the read pattern. I am new to Rust and trying to build my source library to solve future programming tasks.
First, as pointed out by kmdreko, the logic of your function(s) can be greatly simplified (at least based on the information given):
pub async fn read_stream_tcp(stream: TcpStream) -> Result<(), std::io::Error> {
let mut lines = BufReader::new(stream).lines();
while let Some(line) = lines.next().await {
println!("{line:?}");
}
}
Ok(())
Then, to figure out how to make this generic, you can just let the compiler tell you what it needs:
pub async fn read_stream<T>(stream: T) -> Result<(), std::io::Error>
{
let mut lines = BufReader::new(stream).lines();
while let Some(line) = lines.next().await {
println!("{line:?}");
}
Ok(())
}
Notice the lack of where clauses or other constraints on T. The compiler will now complain:
error[E0277]: the trait bound `T: async_std::io::Read` is not satisfied --> src/main.rs:15:36 |
15 | let mut lines = BufReader::new(stream).lines();
| -------------- ^^^^^^ the trait `async_std::io::Read` is not implemented for `T`
| |
| required by a bound introduced by this call
|
note: required by a bound in `async_std::io::BufReader::<R>::new`
--> /home/lucas/.cargo/registry/src/github.com-1ecc6299db9ec823/async-std-1.12.0/src/io/buf_reader.rs:55:9
|
55 | impl<R: io::Read> BufReader<R> {
| ^^^^^^^^ required by this bound in `async_std::io::BufReader::<R>::new`
help: consider restricting type parameter `T`
|
13 | pub async fn read_stream<T: async_std::io::Read>(stream: T) -> Result<(), std::io::Error>
| +++++++++++++++++++++
Applying the compiler's suggestions (the above will result in a follow-up error) yields a full where clause of T: async_std::io::Read + std::marker::Unpin:
pub async fn read_stream<T>(stream: T) -> Result<(), std::io::Error>
where
T: Read + std::marker::Unpin,
{
let mut lines = BufReader::new(stream).lines();
while let Some(line) = lines.next().await {
println!("{line:?}");
}
Ok(())
}
async fn try_it() {
// These will now compile just fine
read_stream(async_std::io::stdin()).await.unwrap();
read_stream(TcpStream::connect("127.0.0.1:8080").await.unwrap()).await.unwrap();
}
I attempted <T: async_std::io::Read> but fuse() and lines() are not implemented
This suggests that you tried replacing BufReader::new(stream) at the same time. You can do that, but you need to tell the compiler that you need something that implements the lines() method. Either make the parameter a fixed type BufReader<T> or make the where clause T: async_std::io::BufRead + std::marker::Unpin for a generic type.

Multiple mutable borrows in Rust

I'm playing around with building a very simple stack based evaluator in Rust. I want the user to be able to define functions later, so I'm storing all operators in a HashMap with closures as values.
use std::collections::HashMap;
pub type Value = i32;
pub struct Evaluator<'a> {
stack: Vec<Value>,
ops: HashMap<String, &'a dyn FnMut(&'a mut Vec<Value>)>,
}
impl<'a> Evaluator<'a> {
pub fn new() -> Evaluator<'a> {
let stack: Vec<Value> = vec![];
let mut ops: HashMap<String, &'a dyn FnMut(&'a mut Vec<Value>)> = HashMap::new();
ops.insert("+".to_string(), &|stack: &'a mut Vec<Value>| {
if let (Some(x), Some(y)) = (stack.pop(), stack.pop()) {
stack.push(y + x);
}
});
Evaluator { stack, ops }
}
pub fn stack(&self) -> &[Value] {
&self.stack
}
pub fn eval(&'a mut self, input: &str) {
let symbols = input
.split_ascii_whitespace()
.collect::<Vec<_>>();
for sym in symbols {
if let Ok(n) = sym.parse::<i32>() {
self.stack.push(n);
} else {
let s = sym.to_ascii_lowercase();
if let Some(f) = self.ops.get(&s) {
f(&mut self.stack);
} else {
println!("error");
}
}
}
}
}
fn main() {
let mut e = Evaluator::new();
e.eval("1 2 +")
}
I'm currently getting two errors:
error[E0499]: cannot borrow `self.stack` as mutable more than once at a time
--> src/sample.rs:34:17
|
10 | impl<'a> Evaluator<'a> {
| -- lifetime `'a` defined here
...
34 | self.stack.push(n);
| ^^^^^^^^^^ second mutable borrow occurs here
...
38 | f(&mut self.stack);
| ------------------
| | |
| | first mutable borrow occurs here
| argument requires that `self.stack` is borrowed for `'a`
error[E0596]: cannot borrow `**f` as mutable, as it is behind a `&` reference
--> src/sample.rs:38:21
|
38 | f(&mut self.stack);
| ^ cannot borrow as mutable
error[E0499]: cannot borrow `self.stack` as mutable more than once at a time
--> src/sample.rs:38:23
|
10 | impl<'a> Evaluator<'a> {
| -- lifetime `'a` defined here
...
38 | f(&mut self.stack);
| --^^^^^^^^^^^^^^^-
| | |
| | `self.stack` was mutably borrowed here in the previous iteration of the loop
| argument requires that `self.stack` is borrowed for `'a`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0499, E0596.
For more information about an error, try `rustc --explain E0499`.
My concern is the first one. I'm not sure what I'm doing wrong as I'm not borrowing them at the same time. Can I tell Rust the previous borrow (self.stack.pop()) is done? Any help appreciated.
I think I solved my problem. The thing I kept coming back to is, "What owns the closures?" In this case I'm using references, but nothing is taking ownership of the data. When I refactored (below) with Box to take ownership, it worked.
I'm curious if there is a way to do this with with just references and/or if my explanation is wrong?
Working code:
use std::collections::HashMap;
pub type Value = i32;
pub struct Evaluator {
stack: Vec<Value>,
ops: HashMap<String, Box<dyn FnMut(&mut Vec<Value>)>>,
}
impl Evaluator {
pub fn new() -> Evaluator {
let stack: Vec<Value> = vec![];
let mut ops: HashMap<String, Box<dyn FnMut(&mut Vec<Value>)>> = HashMap::new();
ops.insert("+".to_string(), Box::new(|stack: &mut Vec<Value>| {
if let (Some(x), Some(y)) = (stack.pop(), stack.pop()) {
stack.push(y + x);
}
}));
Evaluator { stack, ops }
}
pub fn stack(&self) -> &[Value] {
&self.stack
}
pub fn eval(&mut self, input: &str) {
let symbols = input
.split_ascii_whitespace()
.collect::<Vec<_>>();
for sym in symbols {
if let Ok(n) = sym.parse::<i32>() {
self.stack.push(n);
} else {
let s = sym.to_ascii_lowercase();
if let Some(f) = self.ops.get_mut(&s) {
f(&mut self.stack);
} else {
println!("error");
}
}
}
}
}
fn main() {
let mut e = Evaluator::new();
e.eval("1 2 +")
}
You have borrows with conflicting lifetimes:
You are defining a lifetime 'a for the struct in line 5: pub struct Evaluator<'a> {
In line 7, you are stating that ops is a HashMap that holds functions that receive mutable borrows for the whole duration of 'a
Then, in line 28, you are defining an eval method that holds a mutable reference to self for the whole duration of the struct ('a)
The conflict can be solved if you use two different lifetimes, since the time that an operation borrows self should be inherently shorter than the lifetime for the whole evaluation, since in eval you are running a loop and multiple invocations to the operations.
This should fix the issues mentioned above:
pub struct Evaluator<'a, 'b> {
stack: Vec<Value>,
ops: HashMap<String, &'b dyn FnMut(&'b mut Vec<Value>)>,
}
impl<'a, 'b> Evaluator<'a, 'b> {
pub fn new() -> Evaluator<'a> {
let stack: Vec<Value> = vec![];
let mut ops: HashMap<String, &'b dyn FnMut(&'b mut Vec<Value>)> = HashMap::new();

How can I clone a Vec<Box<dyn Trait>>?

I want to implement a function that takes an immutable &Vec reference, makes a copy, sorts the values and prints them.
This is the main code.
trait Foo {
fn value(&self) -> i32;
}
struct Bar {
x: i32,
}
impl Foo for Bar {
fn value(&self) -> i32 {
self.x
}
}
fn main() {
let mut a: Vec<Box<dyn Foo>> = Vec::new();
a.push(Box::new(Bar { x: 3 }));
a.push(Box::new(Bar { x: 5 }));
a.push(Box::new(Bar { x: 4 }));
let b = &a;
sort_and_print(&b);
}
The only way I was able to make it work was this
fn sort_and_print(v: &Vec<Box<dyn Foo>>) {
let mut v_copy = Vec::new();
for val in v {
v_copy.push(val);
}
v_copy.sort_by_key(|o| o.value());
for val in v_copy {
println!("{}", val.value());
}
}
However I want to understand what's happening here and also to make the code shorter.
Question 1
If I try to change let mut v_copy = Vec::new(); to let mut v_copy: Vec<Box<dyn Foo>> = Vec::new(); however that results in various errors that I don't know how to fix.
How do I make this version work and why is it different than the first version?
Attempt 2
Something closer to what I'm looking for is something like this.
let mut v_copy = v.clone(); but this doesn't work. Can this version be fixed?
First, let's annotate the types:
fn sort_and_print(v: &Vec<Box<dyn Foo>>) {
let mut v_copy: Vec<&Box<dyn Foo>> = Vec::new();
for val /* : &Box<dyn Foo> */ in v {
v_copy.push(val);
}
v_copy.sort_by_key(|o: &&Box<dyn Foo>| <dyn Foo>::value(&***o));
for val /* : &Box<dyn Foo> */ in v_copy {
println!("{}", <dyn Foo>::value(&**val));
}
}
Iterating over &Vec<T> produces an iterator over &T (the same as the .iter() method).
Now we can see we can convert it into iterator, by either calling .into_iter() on v and then .collect() (which is what the for loop does), or replace into_iter() with iter() (which is more idiomatic since we're iterating over references):
fn sort_and_print(v: &Vec<Box<dyn Foo>>) {
let mut v_copy: Vec<&Box<dyn Foo>> = v.iter().collect(); // You can omit the `&Box<dyn Foo>` and replace it with `_`, I put it here for clarity.
v_copy.sort_by_key(|o| o.value());
for val in v_copy {
println!("{}", val.value());
}
}
However, we still only have a copy of the reference (&Box<dyn Foo>). Why can't we just clone the vector?
If we try...
fn sort_and_print(v: &Vec<Box<dyn Foo>>) {
let mut v_copy = v.clone();
v_copy.sort_by_key(|o| o.value());
for val in v_copy {
println!("{}", val.value());
}
}
...the compiler yell at us:
warning: variable does not need to be mutable
--> src/main.rs:45:9
|
45 | let mut v_copy = v.clone();
| ----^^^^^^
| |
| help: remove this `mut`
|
= note: `#[warn(unused_mut)]` on by default
error[E0596]: cannot borrow `*v_copy` as mutable, as it is behind a `&` reference
--> src/main.rs:46:5
|
45 | let mut v_copy = v.clone();
| ---------- help: consider changing this to be a mutable reference: `&mut Vec<Box<dyn Foo>>`
46 | v_copy.sort_by_key(|o| o.value());
| ^^^^^^ `v_copy` is a `&` reference, so the data it refers to cannot be borrowed as mutable
WHAT???????????
Well, let's try to specify the type. It can make the compiler smarter.
fn sort_and_print(v: &Vec<Box<dyn Foo>>) {
let mut v_copy: Vec<Box<dyn Foo>> = v.clone();
v_copy.sort_by_key(|o| o.value());
for val in v_copy {
println!("{}", val.value());
}
}
Nope.
error[E0308]: mismatched types
--> src/main.rs:45:41
|
45 | let mut v_copy: Vec<Box<dyn Foo>> = v.clone();
| ----------------- ^^^^^^^^^
| | |
| | expected struct `Vec`, found reference
| | help: try using a conversion method: `v.to_vec()`
| expected due to this
|
= note: expected struct `Vec<Box<dyn Foo>>`
found reference `&Vec<Box<dyn Foo>>`
Well, let's use the compiler's suggestion:
fn sort_and_print(v: &Vec<Box<dyn Foo>>) {
let mut v_copy: Vec<Box<dyn Foo>> = v.to_vec();
v_copy.sort_by_key(|o| o.value());
for val in v_copy {
println!("{}", val.value());
}
}
Grrr!!
error[E0277]: the trait bound `dyn Foo: Clone` is not satisfied
--> src/main.rs:45:43
|
45 | let mut v_copy: Vec<Box<dyn Foo>> = v.to_vec();
| ^^^^^^ the trait `Clone` is not implemented for `dyn Foo`
|
= note: required because of the requirements on the impl of `Clone` for `Box<dyn Foo>`
At least we now have some clues.
What happened here?
Well, like the compiler said, dyn Foo does not implement the Clone trait. Which means that neither does Box<dyn Foo>, and so is Vec<Box<dyn Foo>>.
However, &Vec<Box<dyn Foo>> actually does impl Clone. This is because you can have as many shared references as you want - shared (non-mutable) references are Copy, and every Copy is also Clone. Try it:
fn main() {
let i: i32 = 123;
let r0: &i32 = &i;
let r1: &i32 = <&i32 as Clone>::clone(&r0);
}
So, when we write v.clone(), the compiler asks "is there a method named clone() that takes self of type &Vec<Box<dyn Foo>> (v)?" it first looks for such method on the Clone impl for Vec<Box<dyn Foo>> (because the Clone::clone() takes &self, so for Vec<Box<dyn Foo>> it takes &Vec<Box<dyn Foo>>). Unfortunately, such impl doesn't exist, so it does the magic of autoref (part the process of trying to adjust a method receiver in Rust, you can read more here), and asks the same question for &&Vec<Box<dyn Foo>>. Now we did find a match - <&Vec<Box<dyn Foo>> as Clone>::clone()! So this is what the compiler calls.
What is the return type of the method? Well, &Vec<Box<dyn Foo>>. This will be the type of v_copy. Now we understand why when we specified another type, the compiler got crazy! We can also decrypt the error message when we didn't specify a type: we asked the compiler to call sort_by_key() on a &Vec<Box<dyn Foo>>, but this method requires a &mut Vec<Box<dyn Foo>> (&mut [Box<dyn Foo>], to be precise, but it doesn't matter because Vec<T> can coerce to [T])!
We can also understand the warning about a redundant mut: we never change the reference, so no need to declare it as mutable!
When we called to_vec(), OTOH, the compiler didn't get confused: to_vec() requires the vector's item to implement Clone (where T: Clone), which doesn't happen for Box<dyn Foo>. BOOM.
Now the solution should be clear: we just need Box<dyn Foo> to impl Clone.
Just?...
The first thing we may think about is to give Foo a supertrait Clone:
trait Foo: Clone {
fn value(&self) -> i32;
}
#[derive(Clone)]
struct Bar { /* ... */ }
Not working:
error[E0038]: the trait `Foo` cannot be made into an object
--> src/main.rs:33:31
|
33 | fn sort_and_print(v: &Vec<Box<dyn Foo>>) {
| ^^^^^^^ `Foo` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> src/main.rs:1:12
|
1 | trait Foo: Clone {
| --- ^^^^^ ...because it requires `Self: Sized`
| |
| this trait cannot be made into an object...
Hmm, looks like Clone indeed requires Sized. Why?
Well, because in order to clone something, we need to return itself. Can we return dyn Foo? No, because it can be of any size.
So, let's try to impl Clone for Box<dyn Foo> by hand (we can do that even though Box is not defined in our crate because it is a fundamental type and Foo is local (defined in our crate)).
impl Clone for Box<dyn Foo> {
fn clone(self: &Box<dyn Foo>) -> Box<dyn Foo> {
// Now... What, actually?
}
}
How can we even clone something that can be anything? Clearly we need to forward it to someone else. Who else? Someone who knows how to clone this thing. A method on Foo?
trait Foo {
fn value(&self) -> i32;
fn clone_dyn(&self) -> Box<dyn Foo>;
}
impl Foo for Bar {
fn value(&self) -> i32 {
self.x
}
fn clone_dyn(&self) -> Box<dyn Foo> {
Box::new(self.clone()) // Forward to the derive(Clone) impl
}
}
NOW!
impl Clone for Box<dyn Foo> {
fn clone(&self) -> Self {
self.clone_dyn()
}
}
IT WORKS!!
fn sort_and_print(v: &Vec<Box<dyn Foo>>) {
let mut v_copy = v.clone();
v_copy.sort_by_key(|o| o.value());
for val in v_copy {
println!("{}", val.value());
}
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d6e871711146bc3f34d9710211b4a1dd
Note: The dyn-clone crate from #dtonlay generalizes this idea.
You can make sort_and_print() shorter using Iterator::collect():
fn sort_and_print(v: &[Box<dyn Foo>]) {
let mut v_copy: Vec<_> = v.iter().collect();
v_copy.sort_by_key(|o| o.value());
for val in v_copy {
println!("{}", val.value());
}
}
Playground
As an aside, accepting a vector by reference is usually better expressed as accepting a slice, as explained here, so the above answer accepts a slice.
You can make it even shorter by using the sorted() method from the itertools crate, or in this case its cousin sorted_by_key():
use itertools::Itertools;
fn sort_and_print(v: &[Box<dyn Foo>]) {
for val in v.iter().sorted_by_key(|o| o.value()) {
println!("{}", val.value());
}
}
You almost certainly don't want to clone the vector because it would involve a deep copy, i.e. cloning each Box<dyn Foo>, which is unnecessary, potentially expensive, as well as complicated (as explained in the other answer).

How do I return a boxed iterator that returns boxed iterators of f64?

I'm trying to read a CSV file using the CSV crate and lazily cast all its cells to f64:
use csv::ReaderBuilder; // 1.1.4
fn get_df_iterator(path: &str) {
// Build the CSV reader and iterate over each record casting to f64
let rdr = ReaderBuilder::new()
.delimiter(b'\t')
.from_path(path)
.unwrap();
rdr.into_records().map(|record_result| {
record_result
.unwrap()
.into_iter()
.map(|cell: &str| cell.parse::<f64>().unwrap())
})
}
fn main() {
let m1 = get_df_iterator("df1.csv");
}
playground
I've read that to return types with closures in stable Rust we can use Boxes. I've tried with:
use csv::{Error, ReaderBuilder, StringRecord};
fn get_df_iterator_box(path: &str) -> Box<dyn Iterator<Item = Box<dyn Iterator<Item = f64>>>> {
// Build the CSV reader and iterate over each record.
let rdr = ReaderBuilder::new()
.delimiter(b'\t')
.from_path(path)
.unwrap();
// Returns Box<Iterator<Item = f64>>
let parse_str = |cell: &str| cell.parse::<f64>().unwrap();
let parse_record = |record_result: Result<StringRecord, Error>| {
Box::new(record_result.unwrap().into_iter().map(parse_str))
};
// Box<Iterator<Item = Box<Iterator<Item = f64>>>>
Box::new(rdr.into_records().map(parse_record))
}
fn main() {
let m1 = get_df_iterator_box("df1.csv");
}
error[E0271]: type mismatch resolving `<[closure#src/main.rs:13:24: 15:6] as FnOnce<(std::result::Result<StringRecord, csv::Error>,)>>::Output == Box<(dyn Iterator<Item = f64> + 'static)>`
--> src/main.rs:18:5
|
11 | let parse_str = |cell: &str| cell.parse::<f64>().unwrap();
| ----------------------------------------- the expected closure
...
18 | Box::new(rdr.into_records().map(parse_record))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Map`, found trait object `dyn Iterator`
|
= note: expected struct `Box<Map<StringRecordIter<'_>, [closure#src/main.rs:11:21: 11:62]>>`
found struct `Box<(dyn Iterator<Item = f64> + 'static)>`
= note: required because of the requirements on the impl of `Iterator` for `Map<StringRecordsIntoIter<File>, [closure#src/main.rs:13:24: 15:6]>`
= note: required for the cast to the object type `dyn Iterator<Item = Box<(dyn Iterator<Item = f64> + 'static)>>`
I don't understand what the problem is. It's supposed to return a Box which contains an iterator that returns Boxes of iterators of f64. Here there's another playground with that update! If you want to replicate with the same file I'm using here you can download it.
You can specify the return type of the closure to tell Rust that you are returning a dyn trait:
let parse_record =
|record_result: Result<StringRecord, Error>| -> Box<dyn Iterator<Item = f64>> {
Box::new(record_result.unwrap().into_iter().map(parse_str))
};
An alternative method would be to explicitly cast within the closure:
let parse_record = |record_result: Result<StringRecord, Error>| {
Box::new(record_result.unwrap().into_iter().map(parse_str)) as Box<dyn Iterator<Item = f64>>
};
You could instead return impl trait instead of using dynamic dispatch and avoid this altogether:
fn get_iterator(path: &str) -> impl Iterator<Item = impl Iterator<Item = f64>> { ... }
For more information about returning traits, see What is the correct way to return an Iterator?

Unboxing and inspecting a trait object

Here's a simple application that duplicates 2 times on stdout the contents of stdin:
use std::{
io,
io::{stdin, stdout, Read, Write},
num::NonZeroUsize,
};
fn dup_input(
input: &mut Box<dyn Read>,
output: &mut Box<dyn Write>,
count: NonZeroUsize,
) -> io::Result<()> {
let mut buf = Vec::new();
input.read_to_end(&mut buf)?;
for _idx in 0..count.get() {
output.write_all(&buf)?;
}
Ok(())
}
fn main() {
let mut input: Box<dyn Read> = Box::new(stdin());
let mut output: Box<dyn Write> = Box::new(stdout());
dup_input(&mut input, &mut output, NonZeroUsize::new(2).unwrap())
.expect("Failed to duplicate input");
}
This part works fine. I want to put a unit test on top of this and this is where the problem lies. The closest I've got to build is with the following attempt:
#[cfg(test)]
mod tests {
use super::*;
use std::{any::Any, io::Cursor};
#[test]
fn test() {
let mut input: Box<dyn Read> = Box::new(Cursor::new([b't', b'e', b's', b't', b'\n']));
let mut output: Box<dyn Write + Any> = Box::new(Vec::<u8>::new());
assert!(dup_input(&mut input, &mut output, NonZeroUsize::new(3).unwrap()).is_ok());
assert_eq!(output.downcast::<Vec<u8>>().unwrap().len(), 15);
}
}
but rust 1.41.0 doesn't agree:
$ cargo test
Compiling unbox-example v0.1.0 (/XXX/unbox-example)
error[E0225]: only auto traits can be used as additional traits in a trait object
--> src/main.rs:39:41
|
39 | let mut output: Box<dyn Write + Any> = Box::new(Vec::<u8>::new());
| ----- ^^^
| | |
| | additional non-auto trait
| | trait alias used in trait object type (additional use)
| first non-auto trait
| trait alias used in trait object type (first use)
error[E0308]: mismatched types
--> src/main.rs:41:39
|
41 | assert!(dup_input(&mut input, &mut output, NonZeroUsize::new(3).unwrap()).is_ok());
| ^^^^^^^^^^^ expected trait `std::io::Write`, found a different trait `std::io::Write`
|
= note: expected mutable reference `&mut std::boxed::Box<(dyn std::io::Write + 'static)>`
found mutable reference `&mut std::boxed::Box<(dyn std::io::Write + 'static)>`
error[E0599]: no method named `downcast` found for type `std::boxed::Box<(dyn std::io::Write + 'static)>` in the current scope
--> src/main.rs:43:27
|
43 | assert_eq!(output.downcast::<Vec<u8>>().unwrap().len(), 15);
| ^^^^^^^^ method not found in `std::boxed::Box<(dyn std::io::Write + 'static)>`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0225, E0308, E0599.
For more information about an error, try `rustc --explain E0225`.
error: could not compile `unbox-example`.
To learn more, run the command again with --verbose.
Is there a way to change the unit test without changing the main code? Note: I could have used generics while implementing dup_input and make the problem significantly easier to solve but this code is part of a broader application and I have to use Read/Write trait objects.
Passing a mutable reference to a Box to dup_input is unnecessarily complicated. You can simply pass a mutable reference to the trait object.
use std::{
io,
io::{stdin, stdout, Read, Write},
num::NonZeroUsize,
};
fn dup_input(
input: &mut dyn Read,
output: &mut dyn Write,
count: NonZeroUsize,
) -> io::Result<()> {
let mut buf = Vec::new();
input.read_to_end(&mut buf)?;
for _idx in 0..count.get() {
output.write_all(&buf)?;
}
Ok(())
}
fn main() {
let mut input = stdin();
let mut output = stdout();
dup_input(&mut input, &mut output, NonZeroUsize::new(2).unwrap())
.expect("Failed to duplicate input");
}
With this version, the test can be written like this:
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn test() {
let mut input = Cursor::new([b't', b'e', b's', b't', b'\n']);
let mut output = Vec::<u8>::new();
assert!(dup_input(&mut input, &mut output, NonZeroUsize::new(3).unwrap()).is_ok());
assert_eq!(output.len(), 15);
}
}
We don't need to use Any at all here: output is simply a Vec<u8>.

Resources