Примитивный тип pointer

Сырые указатели (raw pointers) *const T и *mut T

Смотрите также модуль std::ptr.

Работа с сырыми указателями в Rust встречается редко и обычно ограничена несколькими паттернами. Сырые указатели могут быть:

  • Выходящими за границы (out-of-bounds)
  • Невыровненными (unaligned)
  • Нулевыми (null)

Однако при загрузке из или записи в сырой указатель он должен быть валидным для данного доступа и выровненным. При использовании выражений доступа к полю, индексации кортежа, массива или среза на сыром указателе применяются правила арифметики указателей в пределах границ.

Запись через сырой указатель с помощью *ptr = data вызывает drop на старом значении, поэтому если тип имеет деструктор (drop glue) и память ещё не инициализирована, необходимо использовать write - иначе drop будет вызван на неинициализированной памяти.

Используйте функции null и null_mut для создания нулевых указателей, а метод is_null типов *const T и *mut T для проверки на null. Типы *const T и *mut T также определяют метод offset для арифметики указателей.


Распространённые способы создания сырых указателей

1. Приведение ссылки (&T) или изменяемой ссылки (&mut T)

#![allow(unused)]
fn main() {
let my_num: i32 = 10;
let my_num_ptr: *const i32 = &my_num;
let mut my_speed: i32 = 88;
let my_speed_ptr: *mut i32 = &mut my_speed;
}

Чтобы получить указатель на упакованное значение (Box), разыменуйте box:

#![allow(unused)]
fn main() {
let my_num: Box<i32> = Box::new(10);
let my_num_ptr: *const i32 = &*my_num;
let mut my_speed: Box<i32> = Box::new(88);
let my_speed_ptr: *mut i32 = &mut *my_speed;
}

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

2. Потребление box'а (Box<T>)

Функция into_raw потребляет box и возвращает сырой указатель. Она не уничтожает T и не освобождает память.

#![allow(unused)]
fn main() {
let my_speed: Box<i32> = Box::new(88);
let my_speed: *mut i32 = Box::into_raw(my_speed);

// Забрав владение исходным `Box<T>`, мы обязаны позже собрать его для уничтожения
unsafe {
    drop(Box::from_raw(my_speed));
}
}

Примечание: вызов drop здесь для ясности - он указывает, что мы закончили работу с данным значением и его следует уничтожить.

3. Создание с помощью &raw

Вместо приведения ссылки к сырому указателю можно использовать операторы сырого заимствования &raw const (для *const T) и &raw mut (для *mut T). Эти операторы позволяют создавать сырые указатели на поля, на которые нельзя создать ссылку (без возникновения неопределённого поведения), например, на невыровненное поле. Это может быть необходимо при работе с упакованными структурами (packed structs) или неинициализированной памятью.

#![allow(unused)]
fn main() {
#[derive(Debug, Default, Copy, Clone)]
#[repr(C, packed)]
struct S {
    aligned: u8,
    unaligned: u32,
}
let s = S::default();
let p = &raw const s.unaligned; // невозможно с приведением
}

4. Получение из C

#![allow(unused)]
fn main() {
#[allow(unused_extern_crates)]
extern crate libc;

unsafe {
    let my_num: *mut i32 = libc::malloc(size_of::<i32>()) as *mut i32;
    if my_num.is_null() {
        panic!("failed to allocate memory");
    }
    libc::free(my_num as *mut core::ffi::c_void);
}
}

Обычно вы не будете буквально использовать malloc и free из Rust, но C API часто возвращают указатели, поэтому они являются распространённым источником сырых указателей в Rust.


Реализации методов

Методы для *const T

МетодВерсияОписание
is_null(self) -> bool1.0.0 (const: 1.84.0)Возвращает true, если указатель нулевой
cast<U>(self) -> *const U1.38.0 (const: 1.38.0)Приводит к указателю другого типа
try_cast_aligned<U>(self) -> Option<*const U>nightlyПытается привести к указателю другого типа с проверкой выравнивания
with_metadata_of<U>(self, meta: *const U) -> *const UnightlyИспользует адресное значение в новом указателе другого типа
cast_mut(self) -> *mut T1.65.0 (const: 1.65.0)Изменяет константность без изменения типа
addr(self) -> usize1.84.0Получает "адресную" часть указателя
expose_provenance(self) -> usize1.84.0Раскрывает "происхождение" указателя для будущего использования
with_addr(self, addr: usize) -> *const T1.84.0Создаёт новый указатель с заданным адресом и происхождением self
map_addr(self, f: FnOnce(usize) -> usize) -> *const T1.84.0Создаёт новый указатель, отображая адрес self на новый
to_raw_parts(self) -> (*const (), Metadata)nightlyРазбирает (возможно, широкий) указатель на компоненты
as_ref<'a>(self) -> Option<&'a T>1.9.0 (const: 1.84.0)Возвращает None, если указатель нулевой, иначе ссылку на значение
as_ref_unchecked<'a>(self) -> &'a TnightlyВозвращает ссылку на значение за указателем без проверки на null
as_uninit_ref<'a>(self) -> Option<&'a MaybeUninit<T>>nightlyАналогично as_ref, но допускает неинициализированные значения
offset(self, count: isize) -> *const T1.0.0 (const: 1.61.0)Добавляет знаковое смещение к указателю
byte_offset(self, count: isize) -> *const T1.75.0 (const: 1.75.0)Добавляет знаковое смещение в байтах
wrapping_offset(self, count: isize) -> *const T1.16.0 (const: 1.61.0)Добавляет знаковое смещение с оборачивающей арифметикой
wrapping_byte_offset(self, count: isize) -> *const T1.75.0 (const: 1.75.0)Добавляет знаковое смещение в байтах с оборачиванием
mask(self, mask: usize) -> *const TnightlyМаскирует биты указателя согласно маске
offset_from(self, origin: *const T) -> isize1.47.0 (const: 1.65.0)Вычисляет расстояние между двумя указателями
byte_offset_from<U>(self, origin: *const U) -> isize1.75.0 (const: 1.75.0)Вычисляет расстояние в байтах между указателями
offset_from_unsigned(self, origin: *const T) -> usize1.87.0 (const: 1.87.0)Вычисляет расстояние между указателями, где self >= origin
byte_offset_from_unsigned<U>(self, origin: *const U) -> usize1.87.0 (const: 1.87.0)Вычисляет расстояние в байтах, где self >= origin
guaranteed_eq(self, other: *const T) -> Option<bool>nightlyПроверяет, гарантированно ли равны указатели
guaranteed_ne(self, other: *const T) -> Option<bool>nightlyПроверяет, гарантированно ли не равны указатели
add(self, count: usize) -> *const T1.26.0 (const: 1.61.0)Добавляет беззнаковое смещение к указателю
byte_add(self, count: usize) -> *const T1.75.0 (const: 1.75.0)Добавляет беззнаковое смещение в байтах
sub(self, count: usize) -> *const T1.26.0 (const: 1.61.0)Вычитает беззнаковое смещение из указателя
byte_sub(self, count: usize) -> *const T1.75.0 (const: 1.75.0)Вычитает беззнаковое смещение в байтах
wrapping_add(self, count: usize) -> *const T1.26.0 (const: 1.61.0)Добавляет беззнаковое смещение с оборачиванием
wrapping_byte_add(self, count: usize) -> *const T1.75.0 (const: 1.75.0)Добавляет беззнаковое смещение в байтах с оборачиванием
wrapping_sub(self, count: usize) -> *const T1.26.0 (const: 1.61.0)Вычитает беззнаковое смещение с оборачиванием
wrapping_byte_sub(self, count: usize) -> *const T1.75.0 (const: 1.75.0)Вычитает беззнаковое смещение в байтах с оборачиванием
read(self) -> T1.26.0 (const: 1.71.0)Читает значение из self, не перемещая его
read_volatile(self) -> T1.26.0Выполняет volatile чтение значения
read_unaligned(self) -> T1.26.0 (const: 1.71.0)Читает значение из невыровненного указателя
copy_to(self, dest: *mut T, count: usize)1.26.0 (const: 1.83.0)Копирует байты из self в dest (с перекрытием)
copy_to_nonoverlapping(self, dest: *mut T, count: usize)1.26.0 (const: 1.83.0)Копирует байты из self в dest (без перекрытия)
align_offset(self, align: usize) -> usize1.36.0Вычисляет смещение для выравнивания указателя
is_aligned(self) -> bool1.79.0Проверяет, выровнен ли указатель для T
is_aligned_to(self, align: usize) -> boolnightlyПроверяет, выровнен ли указатель на align

Методы для *mut T

МетодВерсияОписание
is_null(self) -> bool1.0.0 (const: 1.84.0)Возвращает true, если указатель нулевой
cast<U>(self) -> *mut U1.38.0 (const: 1.38.0)Приводит к указателю другого типа
try_cast_aligned<U>(self) -> Option<*mut U>nightlyПытается привести к указателю другого типа с проверкой выравнивания
with_metadata_of<U>(self, meta: *const U) -> *mut UnightlyИспользует адресное значение в новом указателе другого типа
cast_const(self) -> *const T1.65.0 (const: 1.65.0)Изменяет константность без изменения типа
addr(self) -> usize1.84.0Получает "адресную" часть указателя
expose_provenance(self) -> usize1.84.0Раскрывает "происхождение" указателя
with_addr(self, addr: usize) -> *mut T1.84.0Создаёт новый указатель с заданным адресом и происхождением
map_addr(self, f: FnOnce(usize) -> usize) -> *mut T1.84.0Создаёт новый указатель, отображая адрес на новый
to_raw_parts(self) -> (*mut (), Metadata)nightlyРазбирает указатель на компоненты
as_ref<'a>(self) -> Option<&'a T>1.9.0 (const: 1.84.0)Возвращает ссылку на значение или None, если null
as_ref_unchecked<'a>(self) -> &'a TnightlyВозвращает ссылку без проверки на null
as_uninit_ref<'a>(self) -> Option<&'a MaybeUninit<T>>nightlyВозвращает ссылку на MaybeUninit
offset(self, count: isize) -> *mut T1.0.0 (const: 1.61.0)Добавляет знаковое смещение
byte_offset(self, count: isize) -> *mut T1.75.0 (const: 1.75.0)Добавляет знаковое смещение в байтах
wrapping_offset(self, count: isize) -> *mut T1.16.0 (const: 1.61.0)Добавляет знаковое смещение с оборачиванием
wrapping_byte_offset(self, count: isize) -> *mut T1.75.0 (const: 1.75.0)Добавляет знаковое смещение в байтах с оборачиванием
mask(self, mask: usize) -> *mut TnightlyМаскирует биты указателя
as_mut<'a>(self) -> Option<&'a mut T>1.9.0 (const: 1.84.0)Возвращает изменяемую ссылку или None, если null
as_mut_unchecked<'a>(self) -> &'a mut TnightlyВозвращает изменяемую ссылку без проверки на null
as_uninit_mut<'a>(self) -> Option<&'a mut MaybeUninit<T>>nightlyВозвращает изменяемую ссылку на MaybeUninit
guaranteed_eq(self, other: *mut T) -> Option<bool>nightlyПроверяет гарантированное равенство указателей
guaranteed_ne(self, other: *mut T) -> Option<bool>nightlyПроверяет гарантированное неравенство указателей
offset_from(self, origin: *const T) -> isize1.47.0 (const: 1.65.0)Вычисляет расстояние между указателями
byte_offset_from<U>(self, origin: *const U) -> isize1.75.0 (const: 1.75.0)Вычисляет расстояние в байтах
offset_from_unsigned(self, origin: *const T) -> usize1.87.0 (const: 1.87.0)Вычисляет расстояние (self >= origin)
byte_offset_from_unsigned<U>(self, origin: *mut U) -> usize1.87.0 (const: 1.87.0)Вычисляет расстояние в байтах (self >= origin)
add(self, count: usize) -> *mut T1.26.0 (const: 1.61.0)Добавляет беззнаковое смещение
byte_add(self, count: usize) -> *mut T1.75.0 (const: 1.75.0)Добавляет беззнаковое смещение в байтах
sub(self, count: usize) -> *mut T1.26.0 (const: 1.61.0)Вычитает беззнаковое смещение
byte_sub(self, count: usize) -> *mut T1.75.0 (const: 1.75.0)Вычитает беззнаковое смещение в байтах
wrapping_add(self, count: usize) -> *mut T1.26.0 (const: 1.61.0)Добавляет беззнаковое смещение с оборачиванием
wrapping_byte_add(self, count: usize) -> *mut T1.75.0 (const: 1.75.0)Добавляет беззнаковое смещение в байтах с оборачиванием
wrapping_sub(self, count: usize) -> *mut T1.26.0 (const: 1.61.0)Вычитает беззнаковое смещение с оборачиванием
wrapping_byte_sub(self, count: usize) -> *mut T1.75.0 (const: 1.75.0)Вычитает беззнаковое смещение в байтах с оборачиванием
read(self) -> T1.26.0 (const: 1.71.0)Читает значение
read_volatile(self) -> T1.26.0Выполняет volatile чтение
read_unaligned(self) -> T1.26.0 (const: 1.71.0)Читает из невыровненного указателя
copy_to(self, dest: *mut T, count: usize)1.26.0 (const: 1.83.0)Копирует в dest (с перекрытием)
copy_to_nonoverlapping(self, dest: *mut T, count: usize)1.26.0 (const: 1.83.0)Копирует в dest (без перекрытия)
copy_from(self, src: *const T, count: usize)1.26.0 (const: 1.83.0)Копирует из src (с перекрытием)
copy_from_nonoverlapping(self, src: *const T, count: usize)1.26.0 (const: 1.83.0)Копирует из src (без перекрытия)
drop_in_place(self)1.26.0Выполняет деструктор значения
write(self, val: T)1.26.0 (const: 1.83.0)Записывает значение без чтения старого
write_bytes(self, val: u8, count: usize)1.26.0 (const: 1.83.0)Заполняет память байтом (аналог memset)
write_volatile(self, val: T)1.26.0Выполняет volatile запись
write_unaligned(self, val: T)1.26.0 (const: 1.83.0)Записывает в невыровненный указатель
replace(self, src: T) -> T1.26.0 (const: 1.88.0)Заменяет значение, возвращая старое
swap(self, with: *mut T)1.26.0 (const: 1.85.0)Меняет местами значения двух указателей
align_offset(self, align: usize) -> usize1.36.0Вычисляет смещение для выравнивания
is_aligned(self) -> bool1.79.0Проверяет выравнивание для T
is_aligned_to(self, align: usize) -> boolnightlyПроверяет выравнивание на align

Методы для срезов *const [T] и *mut [T]

МетодТипВерсияОписание
len(self) -> usizeоба1.79.0 (const)Возвращает длину сырого среза
is_empty(self) -> boolоба1.79.0 (const)Проверяет, пуст ли срез
as_ptr(self) -> *const T*const [T]nightlyВозвращает указатель на буфер среза
as_mut_ptr(self) -> *mut T*mut [T]nightlyВозвращает изменяемый указатель на буфер среза
as_array<const N: usize>(self) -> Option<*const [T; N]>*const [T]1.93.0 (const)Преобразует в указатель на массив
as_mut_array<const N: usize>(self) -> Option<*mut [T; N]>*mut [T]1.93.0 (const)Преобразует в изменяемый указатель на массив
get_unchecked<I>(self, index: I) -> *const Output*const [T]nightlyВозвращает указатель на элемент без проверки границ
get_unchecked_mut<I>(self, index: I) -> *mut Output*mut [T]nightlyВозвращает изменяемый указатель на элемент без проверки границ
split_at_mut(self, mid: usize) -> (*mut [T], *mut [T])*mut [T]nightlyДелит изменяемый срез на две части
split_at_mut_unchecked(self, mid: usize) -> (*mut [T], *mut [T])*mut [T]nightlyДелит изменяемый срез без проверки границ
as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit<T>]>обаnightlyВозвращает срез MaybeUninit (разделяемый)
as_uninit_slice_mut<'a>(self) -> Option<&'a mut [MaybeUninit<T>]>*mut [T]nightlyВозвращает изменяемый срез MaybeUninit

Реализации трейтов

Общие трейты для *const T и *mut T

Трейт*const T*mut TПримечания
CloneВозвращает дубликат значения
CopyТип является копируемым
DebugФорматирование для отладки
DefaultВозвращает null() / null_mut()
EqРавенство указателей - отношение эквивалентности
HashХеширование по адресу
OrdСравнение по адресу
PartialEqРавенство по адресу
PartialOrdСравнение по адресу
PointerФорматирование как указатель
!SendНе является Send
!SyncНе является Sync
UnpinЯвляется Unpin
UnwindSafeБезопасен при раскрутке стеков

Специальные трейты

ТрейтДляОписание
AtomicPrimitive*mut TАтомарные операции с указателями
From<*mut T>AtomicPtr<T>Преобразование *mut T в AtomicPtr<T>
CoerceUnsizedразличныеПриведение размера указателей
DispatchFromDyn*const T, *mut TДинамическая диспетчеризация
FreezeобаГарантирует неизменяемость
PinCoerceUnsizedобаПриведение размера закреплённых указателей
VaArgSafeобаБезопасен для variadic функций

Автоматические реализации трейтов

  • RefUnwindSafe - реализуется, когда T: RefUnwindSafe + ?Sized

Особенности безопасности

  1. Большинство операций с сырыми указателями помечены как unsafe - компилятор не может проверить их безопасность.
  2. Проверка выравнивания - многие операции требуют правильного выравнивания указателя.
  3. Проверка границ - указатели должны оставаться в пределах выделенной памяти.
  4. Проверка на null - многие методы имеют варианты с проверкой и без проверки на null.
  5. Происхождение (provenance) - современные API (addr, with_addr) учитывают происхождение указателей для строгой модели памяти.

Примеры использования

#![allow(unused)]
fn main() {
// Безопасное создание и использование сырых указателей
let x = 42;
let ptr: *const i32 = &x;

unsafe {
    if let Some(val) = ptr.as_ref() {
        assert_eq!(*val, 42);
    }
}

// Арифметика указателей
let arr = [1, 2, 3, 4, 5];
let ptr = arr.as_ptr();

unsafe {
    let ptr2 = ptr.add(2); // Указатель на третий элемент
    assert_eq!(*ptr2, 3);
}

// Работа с изменяемыми указателями
let mut arr = [1, 2, 3];
let ptr = arr.as_mut_ptr();

unsafe {
    *ptr.add(1) = 10; // Изменяем второй элемент
}
assert_eq!(arr, [1, 10, 3]);
}

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