Насколько я понимаю, стандартный (единственный?) способ сделать нулевой указатель в Rust — это std::ptr::null.

Однако эта функция объявлена ​​следующим образом.

pub const fn null<T>() -> *const T

В этом объявлении неявно предполагается, что T имеет фиксированный размер (иначе это было бы T: ?Sized). Как следствие, эту функцию невозможно использовать, например, с *const str или *const [u32]. тестировать на игровой площадке

Есть ли веская причина для исключения неразмерных типов? Что плохого в желании создать нуль *const str?

7
Pierre-Antoine 20 Дек 2019 в 17:24

1 ответ

Указатель на неразмерный тип — это толстый указатель с двумя компонентами: указатель и метаданные типа (длина для срезов и указатель vtable для трейт-объектов; в будущем Rust может разрешить другие виды метаданных). null подразумевает значение только для части указателя; нет очевидного выбора для другого значения. (Вы можете подумать, что 0 является очевидным для длины нулевого указателя слайса, и я вижу аргумент, но если указатель нулевой, вряд ли имеет значение, сколько там вещей; вы все равно не можете разыменовать его, поэтому размер 0 не требуется для обеспечения безопасности.)

Невозможно создать нулевой указатель на трейт-объект, но начиная с Rust 1.42 вы можете использовать ptr::slice_from_raw_parts для создания нулевого указателя на срез. Предположим, что длина среза равна 0:

use std::ptr;
fn main() {
    let p: *const [u32] = ptr::slice_from_raw_parts(ptr::null(), 0);
    println!("{:?}", p);
}

Для str нет эквивалентной функции, но вы можете создать ее, создав null *const [u8] и приведя его к as.

Эта функция (или связанная с ней функция slice_from_raw_parts_mut) — единственный способ правильно создать нулевой указатель на срез. Обычный способ получить необработанный указатель — привести ссылку, но ссылки никогда не могут быть нулевыми.

8
trent 22 Апр 2020 в 03:27
2
Интересно, что slice_from_raw_parts безопасен - причина в том, что его почти невозможно использовать, поскольку функции принимают ссылку, а не указатель, и unsafe требуется для перехода от указателя к ссылке.
 – 
Matthieu M.
20 Дек 2019 в 18:40
1
В чем проблема с нулевым толстым указателем? Вы пишете, что "нет очевидного выбора для [размера]", а я бы наоборот сказал, что нет неправильного значения для размера, так как размер не имеет значения для нулевого указателя ...
 – 
Pierre-Antoine
22 Дек 2019 в 01:47
@matthieu-m согласился, slice_from_raw_parts может привести к "неправильному" *const [T] из "хорошего" *const T, если предоставлен неправильный размер, поэтому я думаю, что это должно быть помечено как небезопасное...
 – 
Pierre-Antoine
22 Дек 2019 в 01:49
1
@ Пьер-Антуан: На ​​самом деле, я был согласен НЕ отмечать это unsafe. Да, он может произвести неправильный *const [T] из хорошего *const T... но вы не можете использовать этот *const [T] без unsafe, чтобы преобразовать его в &[T] или &mut [T].
 – 
Matthieu M.
22 Дек 2019 в 15:14
@Pierre-Antoine Поскольку неправильной длины нет, какая длина должна возвращаться null? Нуль? Один? Что-то произвольное? Предоставление метаданных предполагает некоторое намерение разыменовать указатель, что явно неверно, поэтому я утверждаю, что нулевой указатель среза (или нулевой указатель трейт-объекта), вероятно, является следствием ошибки проектирования. В любом случае вам, вероятно, следует использовать Option<&[T]> вместо *const [T].
 – 
trent
3 Янв 2020 в 19:46