This is a simplified example of my enum
:
#[derive(Debug, Clone, Copy)]
enum Data<'a> {
I32(&'a [i32]),
F64(&'a [f64]),
}
I use the enum
to store different slice types (not only &[i32]
and &[f64]
as in the example above, but many more) to the same vector Vec<Data<'a>>
. I need a way to iterate through the slice values (either &[i32]
or &[f64]
, whatever is stored in the enum
) converting all values to String
. The following code shows what in principle I would like to achieve, but it does not work:
impl<'a> Data<'a> {
fn iter_to_string(&self) -> impl Iterator<Item = String> {
match self {
Data::I32(data) => data.iter().map(|&x| x.to_string()),
Data::F64(data) => data.iter().map(|&x| x.to_string()),
}
}
}
error[E0308]: match arms have incompatible types
--> src/main.rs:9:9
|
9 | / match self {
10 | | Data::I32(data) => data.iter().map(|&x| x.to_string()),
11 | | Data::F64(data) => data.iter().map(|&x| x.to_string()),
| | ----------------------------------- match arm with an incompatible type
12 | | }
| |_________^ expected i32, found f64
|
= note: expected type `std::iter::Map<std::slice::Iter<'_, i32>, [closure@src/main.rs:10:48: 10:66]>`
found type `std::iter::Map<std::slice::Iter<'_, f64>, [closure@src/main.rs:11:48: 11:66]>`
You have two options:
You can't have both static dispatch and a lazy iterator, because that requires the compiler to produce the code path for to_string()
at compile time where the correct choice is only known at runtime.
To use dynamic dispatch, you can create an iterator over trait objects.
use std::fmt::Display;
struct DisplayIter<'iter> {
inner_iter: Box<Iterator<Item=&'iter dyn Display> + 'iter>,
}
impl<'iter> Iterator for DisplayIter<'iter> {
type Item = String;
fn next(&mut self) -> Option<String> {
self.inner_iter.next().map(|val| format!("{}", val))
}
}
In order to use it on a slice iterator, though, you'll need to transform each reference into a trait object reference, such as
data.iter().map(|x| x as &dyn Display)
Just collect the results of the map
you're already doing, and return a owned iterator over the result. This has the downside of allocating, but it solves the issue of needing to choose the code path at compile-time.
data.iter().map(|&x| x.to_string()).collect::<Vec<_>>().into_iter()
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.