Nano Hash - криптовалюты, майнинг, программирование

Как написать правильную сигнатуру универсальной функции при заимствовании данных по нескольким признакам

При разработке частного проекта я столкнулся с жизненной проблемой, связанной с заимствованием одного и того же объекта над несколькими структурами и характеристиками. Это набор урезанных определений, которые я использовал:

trait WorkspaceLog {
    fn get(&self) -> usize;
}

struct TheLog<'a>(&'a FilesystemOverlay);

impl<'a> WorkspaceLog for TheLog<'a> {
    fn get(&self) -> usize {
        (self.0).0
    }
}

trait WorkspaceController<'a> {
    type Log: WorkspaceLog;
    fn get_log(&'a self) -> Self::Log;
}

struct FilesystemOverlay(usize);

struct FSWorkspaceController<'a>(&'a mut FilesystemOverlay);

impl<'a> WorkspaceController<'a> for FSWorkspaceController<'a> {
    type Log = TheLog<'a>;

    fn get_log(&'a self) -> Self::Log {
        TheLog(&*self.0)
    }
}

trait AsWorkspaceController<'a> {
    type Controller: WorkspaceController<'a>;

    fn get_controller(self) -> Self::Controller;
}

impl<'a> AsWorkspaceController<'a> for &'a mut FilesystemOverlay {
    type Controller = FSWorkspaceController<'a>;

    fn get_controller(self) -> FSWorkspaceController<'a> {
        FSWorkspaceController(self)
    }
}

Все идет нормально. Это в основном позволяет мне заимствовать mut ref для FilesystemOverlay в качестве другого интерфейса, обеспечивая дополнительную функциональность. Этот интерфейс, в свою очередь, позволяет мне по существу заимствовать то же самое, что и еще один элемент, который предоставляет окончательные данные. Это работает до тех пор, пока я напрямую использую FilesystemOverlay:

fn init1(control_dir: &mut FilesystemOverlay) -> usize {
    let controller = control_dir.get_controller();
    let log = controller.get_log();
    log.get()
}

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

fn init2<'a: 'b, 'b, O>(control_dir: O) -> usize
    where O: AsWorkspaceController<'b>+'a {
    let controller = control_dir.get_controller();
    let log = controller.get_log();
    log.get()
}

fn main() {
    let mut control_dir = FilesystemOverlay(5);
    dbg!(init1(&mut control_dir));
    dbg!(init2(&mut control_dir));
}

Я пробовал несколько подходов, но пока не смог определить правильную сигнатуру init2. Это ошибка, которую я получаю:

error[E0597]: `controller` does not live long enough
  --> test.rs:53:15
   |
53 |     let log = controller.get_log();
   |               ^^^^^^^^^^ borrowed value does not live long enough
54 |     log.get()
55 | }
   | - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'b as defined on the function body at 50:18...
  --> test.rs:50:18
   |
50 | fn init2<'a: 'b, 'b, O>(control_dir: O) -> usize
   |                  ^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0597`.

Это полный код ржавой площадки.

Итак, как мне изменить подпись init2, чтобы компилятор понимал, что контроллер может быть удален после вызова log.get ()? Нужны ли мне и другие изменения в перечисленных выше типах?

Изменить: я провел несколько дополнительных экспериментов и это лучшее, что мне удалось создать. У этого есть два времени жизни и подпись с поздним связыванием, но она по-прежнему выдает предупреждение о UB. Кто-нибудь понимает почему?


  • Должен WorkspaceController::get_log занять себя, или он может стать владельцем? 18.02.2019
  • Спасибо @eggyal за предложение! Да, это приведет к созданию пригодной для использования версии кода (что-то вроде эти строки), но требует изменения уже существующей характеристики плюс все сайты вызовов, чего я бы предпочел избежать. Тем не менее, я попробую это сделать в своем проекте, возможно, это приведет к еще лучшему коду! 18.02.2019

Ответы:


1

С помощью хорошего и знающего человека на GitHub мне удалось создать рабочую версию кода, см. https://github.com/rust-lang/rust/issues/58868. Ключевым моментом было использование свободного времени жизни, связанного с объявлением типа Controller внутри AsWorkspaceController:

trait AsWorkspaceController<'a> {
    type Controller: for<'b> WorkspaceController<'b>+'a;

    fn get_controller(&'a mut self) -> Self::Controller;
}

См. Полный код на площадке.

03.03.2019
Новые материалы

Кластеризация: более глубокий взгляд
Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

Как написать эффективное резюме
Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

Частный метод Python: улучшение инкапсуляции и безопасности
Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

Как я автоматизирую тестирование с помощью Jest
Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..