Возврат объекта в штучной упаковке из функции - PullRequest
0 голосов
/ 05 июля 2019

Я использую черты объектов для абстрагирования над ядром базы данных. У меня есть черты Database и Snapshot, которые могут быть реализованы для разных механизмов баз данных, но я не могу понять, как вернуть объект черты Snapshot без использования unsafe.

use std::marker::PhantomData;
use std::mem;
use std::sync::Arc;

pub trait Database: Send + Sync + 'static {
    fn snapshot(&self) -> Box<dyn Snapshot>;
}

trait Snapshot: 'static {
    fn foo(&self);
}

struct DB {}

struct DBSnapshot<'a> {
    _lifetime: PhantomData<&'a ()>,
}

impl DB {
    fn snapshot(&self) -> DBSnapshot {
        DBSnapshot {
            _lifetime: PhantomData,
        }
    }
}

struct DBWrapper {
    db: Arc<DB>,
}

impl Database for DBWrapper {
    fn snapshot(&self) -> Box<dyn Snapshot> {
        Box::new(DBWrapperSnapshot {
            snapshot: self.db.snapshot(),
            // Will work with `transmute`
            // snapshot: unsafe { mem::transmute(self.db.snapshot()) },
            db: Arc::clone(&self.db),
        })
    }
}

struct DBWrapperSnapshot {
    snapshot: DBSnapshot<'static>,
    db: Arc<DB>,
}

impl Snapshot for DBWrapperSnapshot {
    fn foo(&self) {}
}

Без небезопасного я получаю ошибку:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
  --> src/main.rs:32:35
   |
32 |                 snapshot: self.db.snapshot(),
   |                                   ^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 30:9...
  --> src/main.rs:30:9
   |
30 | /         fn snapshot(&self) -> Box<dyn Snapshot> {
31 | |             Box::new(DBWrapperSnapshot {
32 | |                 snapshot: self.db.snapshot(),
33 | |                 // Will work with `transmute`
...  |
36 | |             })
37 | |         }
   | |_________^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:32:27
   |
32 |                 snapshot: self.db.snapshot(),
   |                           ^^^^^^^
   = note: but, the lifetime must be valid for the static lifetime...
   = note: ...so that the expression is assignable:
           expected DBSnapshot<'static>
              found DBSnapshot<'_>

Ошибка вполне разумна, но можно ли здесь избежать использования transmute? Потому что я хочу быть уверен, что поле snapshot в DBWrapperSnapshot не изживет ссылку на self.db. Ссылка на детская площадка

...