Примитивный тип 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, включая проверку выравнивания, границ и времени жизни.