Безопасно ли использовать замыкание для получения необработанного указателя из Option <& T>? - PullRequest
1 голос
/ 24 марта 2019

У меня есть Option<&T>, и я хотел бы иметь необработанный *const T, который равен нулю, если опция была None. Я хочу обернуть вызов FFI, который принимает указатель на объект, выделенный в Rust.

Кроме того, используемый мной интерфейс FFI имеет семантику заимствования (я выделяю что-то и передаю указатель на него), а не семантику владения

extern "C" {
    // Parameter may be null
    fn ffi_call(*const T);
}

fn safe_wrapper(opt: Option<&T>) {
    let ptr: *const T = ???;
    unsafe { ffi_call(ptr) }
}

Я мог бы использовать для этого оператор match, но этот метод кажется очень многословным.

let ptr = match opt {
    Some(inner) => inner as *const T,
    None => null(),
};

Я мог бы также сопоставить ссылку с указателем, затем использовать unwrap_or.

let ptr = opt.map(|inner| inner as *const T).unwrap_or(null());

Однако меня беспокоит, что указатель может быть признан недействительным, поскольку он проходит через замыкание. Гарантирует ли Rust, что окончательный указатель будет указывать на то же, что и исходная ссылка? Если T равно Copy, это меняет семантику значимым образом? Есть ли лучший способ, которым я пропускаю?

1 Ответ

2 голосов
/ 24 марта 2019

Да, это безопасно.Я бы написал это так:

use std::ptr;

fn safe_wrapper(opt: Option<&u8>) {
    let p = opt.map_or_else(ptr::null, |x| x);
    unsafe { ffi_call(p) }
}

Если вы обнаружите, что пишете это много, вы можете превратить это в черту и сократить до одного вызова метода.

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

Это может быть, если вы каким-либо образом его аннулируетеПоскольку функция берет ссылку, вы точно знаете, что указанное значение будет действительным в течение всего времени вызова функции - это цель средства проверки заимствования в Rust.

Единственный способ, которым указатель становитсяНедопустимо, если вы измените значение указателя (например, вы добавите к нему смещение).Поскольку вы этого не делаете, это нормально.

Гарантирует ли Rust, что окончательный указатель будет указывать на то же, что и исходная ссылка?

Это зависит от того, что вы подразумеваете под "финалом".Преобразование ссылки на указатель всегда приведет к тому, что оба значения будут содержать одно и то же место в памяти.Все остальное было бы преднамеренно злонамеренным, и никто бы никогда не использовал Rust для начала.

Если T равно Copy, значит ли это изменить семантику значимым образом?

Нет.Кроме того, речь идет о &T, то есть всегда Copy

См. Также:


используемый мной интерфейс FFI имеет семантику заимствования (я выделяю что-то и передаю указатель на него ), а не семантика владения

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

Эта функция C становится владельцем:

void string_free(char *)

Эта функция C занимает:

size_t string_len(char *)

Оба указателя имеют указатель.Rust улучшает эту ситуацию, четко разграничивая, что такое заем и передача права собственности.

extern "C" {
    // Parameter may be null
    fn ffi_call(*const T);
}

Этот код не имеет смысла;он не определяет универсальный тип T, и функции FFI в любом случае не могут иметь универсальные типы.

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