Как именно PhantomData работает в Rust? - PullRequest
1 голос
/ 19 апреля 2020

Я нахожу концепцию PhantomData в Rust довольно запутанной. Я широко использую его, чтобы ограничить время жизни объектов в моем коде на основе FFI, и я до сих пор не уверен, правильно ли я это делаю. Например, я не хочу, чтобы экземпляр MyStruct пережил экземпляр Context:

// FFI declarations and types
mod ffi {
    use std::ffi::c_void;
    pub type handle_t = *const c_void;
    // ...
}

// A wrapper structure for some context created and maintained
// inside the C library
struct Context {
    // ...
}

// Handle is only valid as long as the Context is alive.
// Hence, I use the PhantomData marker to constrain its lifetime.
struct MyStruct<'a> {
    marker: PhantomData<&'a Context>,
    handle: ffi::handle_t,
}

impl<'a> MyStruct<'a> {
    fn new(context: &'a Context) -> Self {
        let handle: ffi::handle_t = context.new_handle();
        MyStruct {
            marker: PhantomData,
            handle
        }
    }
}

fn main() {
    // Initialize the context somewhere inside the C library
    let ctx = Context::new(unsafe {ffi::create_context()});

    // Create an instance of MyStruct
    let my_struct = MyStruct::new(&ctx);

    // ...
}

Я не совсем понимаю следующее:

  1. Что это за вещь marker: PhantomData, синтаксически? Я имею в виду, что это не похоже на конструктор, который я бы ожидал, что-то вроде PhantomData{} или PhantomData().

  2. Для целей отслеживания в течение жизни, делает PhantomData даже заботиться о фактическом типе в объявлении marker? Я попытался изменить его на PhantomData<&'a usize>, и он все еще работал.

  3. В объявлении моего метода MyStruct::new(), если я забуду явно указать время жизни 'a для context аргумент, маги c из PhantomData исчезают, и становится нормальным сбросить Context до MyStruct. Это довольно коварно; компилятор даже не выдает предупреждение. Какой срок жизни он назначает marker тогда и почему?

  4. Относится к предыдущему вопросу; если существует несколько входных ссылочных аргументов с потенциально разными временами жизни, как PhantomData определяет, какое время жизни использовать?

1 Ответ

4 голосов
/ 19 апреля 2020

Что это за синтаксически эта вещь marker: PhantomData? Я имею в виду, что это не похоже на конструктор, который я бы ожидал, что-то вроде PhantomData{} или PhantomData().

Вы можете определить структуру с нулевым полем, например:

struct Foo;

И создайте его экземпляр следующим образом:

let foo: Foo = Foo;

И тип, и значение имеют имя Foo.

Для целей отслеживания жизни, заботится ли PhantomData о фактическом типе в объявлении маркера? Я попытался изменить его на PhantomData<&'a usize>, и он все еще работал.

В PhantomData нет ничего особенного, кроме того, что не является ошибкой то, что его аргумент типа не используется (см. the источник ). Это поведение разрешается с помощью атрибута #[lang = "phantom_data"], который для этой цели является просто ловушкой в ​​компиляторе.

В объявлении моего метода MyStruct::new(), если я забуду явно указать 'a время жизни для аргумента context, маги c из PhantomData исчезают, и становится нормально сбросить Context до MyStruct. Это довольно коварно; компилятор даже не выдает предупреждение. Какой срок жизни он назначает marker тогда и почему?

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

В объявлении моего метода MyStruct::new(), если я забуду явно указать время жизни 'a для аргумента context, Маги c из PhantomData исчезают, и становится нормально сбросить Context до MyStruct. Это довольно коварно; компилятор даже не выдает предупреждение. Какой срок жизни он назначает marker тогда и почему?

Я не совсем уверен, понимаю ли я этот вопрос. PhantomData ничего не делает - это просто способ сообщить компилятору, что вы используете данные определенным образом, и вы можете express точно получить эту информацию. Обратите внимание, что даже если вы express неправильно ограничили ограничения, возможно ввести небезопасную память, только если у вас также есть код unsafe. Правильное выражение времени жизни в PhantomData является частью создания безопасной абстракции вокруг небезопасного кода.

...