Как я могу реализовать итератор над перечислением, которое содержит значения срезов разных типов, преобразуя все значения в `String`? - PullRequest
0 голосов
/ 15 февраля 2019

Это упрощенный пример моего перечисления:

#[derive(Debug, Clone, Copy)]
enum Data<'a> {
    I32(&'a [i32]),
    F64(&'a [f64]),
}

Я использую enum для хранения различных типов срезов (не только &[i32] и &[f64], как в примере выше, но и многих других).больше) к тому же вектору Vec<Data<'a>>.Мне нужен способ перебирать значения срезов (либо &[i32], либо &[f64], независимо от того, что хранится в enum), преобразуя все значения в String.Следующий код показывает, чего в принципе я хотел бы достичь, но это не работает:

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]>`

1 Ответ

0 голосов
/ 15 мая 2019

У вас есть два варианта:

  1. Динамическая отправка
  2. Неразлучный итератор

Вы не можете иметь и статическую рассылку, и ленивуюитератор, поскольку для этого требуется, чтобы компилятор генерировал путь к коду для to_string() во время компиляции, когда правильный выбор известен только во время выполнения.

Динамическая диспетчеризация

Чтобы использовать динамическую диспетчеризацию, вы можетесоздайте итератор для объектов признаков.

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))
  }
}

Чтобы использовать его на итераторе срезов, вам необходимо преобразовать каждую ссылку в ссылку на объект свойств, например

data.iter().map(|x| x as &dyn Display)

Не ленивый итератор

Просто соберите результаты map, который вы уже делаете, и верните свой результат итератору.Это имеет недостатки при распределении, но решает проблему необходимости выбора пути кода во время компиляции.

data.iter().map(|&x| x.to_string()).collect::<Vec<_>>().into_iter()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...