Превратите метод generi c в безопасный метод для типажных объектов - PullRequest
1 голос
/ 13 июля 2020

Я хотел бы создать адаптер, который удаляет общие c параметры (для создания объекта-признака), как в приведенном ниже примере.

use std::ops::Deref;

fn make_dyn_box<I, S>(iter_in: I)
where
    I: Iterator<Item = S>,
    S: Deref<Target = u8>,
{
    let mut iter_out = iter_in.map(
        |s| -> Box<dyn Deref<Target = u8>> {Box::new(s)}
    );
    take_dyn_box(&mut iter_out)
}

fn take_dyn_box<'a: 'b, 'b>(
    iter: &'a mut (dyn 'a + Iterator<Item = Box<dyn 'b + Deref<Target = u8>>>),
) { }

Есть ли способ выполнить sh это без выделение кучи с использованием только безопасного кода и без внешних зависимостей?

Ниже представлено представление о том, что я хочу, но программа проверки заимствований не позволяет этого.

use std::ops::Deref;

fn make_dyn<I, S>(iter_in: I)
where
    I: Iterator<Item = S>,
    S: Deref<Target = u8>,
{
    let mut item = None;
    let item = &mut item;
    let mut iter_out = iter_in.map(|s| -> &dyn Deref<Target = u8> {
        item.replace(s);
        Option::as_ref(item).unwrap()
    });
    take_dyn(&mut iter_out)
}

fn take_dyn<'a: 'b, 'b>(
    iter: &'a mut (dyn 'a + Iterator<Item = &'b (dyn 'b + Deref<Target = u8>)>),
) { }

1 Ответ

1 голос
/ 13 июля 2020

Один простой способ сделать это - потребовать, чтобы итератор ввода возвращал ссылки. Это компилирует:

fn make_dyn<'b, I, S>(iter_in: I)
where
    I: Iterator<Item = &'b S>,
    S: Deref<Target = u8> + 'b,
{
    let mut iter_out = iter_in.map(|s| -> &dyn Deref<Target = u8> {
        s as _
    });
    
    take_dyn(&mut iter_out)
}

fn take_dyn<'a: 'b, 'b>(
    _iter: &'a mut (dyn 'a + Iterator<Item = &'b (dyn 'b + Deref<Target = u8>)>),
) { }

Обратите внимание, что это хороший стиль, когда адаптеры итераторов возвращают итераторы, которыми можно управлять в дальнейшем:

fn make_dyn_<'b, I, S>(iter_in: I) -> impl Iterator<Item = &'b (dyn 'b + Deref<Target = u8>)>
where
    I: Iterator<Item = &'b S>,
    S: Deref<Target = u8> + 'b,
{
    iter_in.map(|s| -> &dyn Deref<Target = u8> {
        s as _
    })
}

(Вы также можете определить это как generi c структура, реализующая черту Iterator.)

Теперь: если вы не хотите требовать, чтобы итератор ввода возвращал ссылки, тогда нет возможности вернуть ваш новый итератор.

Что в примере кода вы создаете небольшой буфер внутри своего итератора и возвращаете на него ссылки.

Если этот буфер хранится в вашей структуре итератора, то, что вы пытаетесь создать, называется итератор потоковой передачи и не может быть реализован в настоящее время. Это очень длинное сообщение в блоге объясняет, почему; по сути, это потребует больших и сложных расширений системы типов Rust.

Вы можете сделать что-то подобное, если вы измените свой код, чтобы пользователи передавали замыкания в ваши функции. Затем вы контролируете, когда вызываются замыкания, поэтому вы можете сохранить возвращенные значения в буфере и передавать ссылки на буфер в замыкание. Но это не так эргономично c, как обычный Iterator интерфейс.

Это вроде того, что вы сделали со своим примером кода ... Я не совсем уверен, почему это не работает . Если вы изменили take_dyn на одиночный &'b (dyn 'b + Deref<Target = u8>)> и неоднократно вызывали его, это должно работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...