Небезопасный трейт
Небезопасный трейт объявляется с помощью ключевого слова unsafe
перед словом trait. Такой трейт накладывает
особые обязательства на того, кто его реализует: реализация
должна соблюдать определённые инварианты, которые компилятор
не в состоянии проверить. Если тип реализует небезопасный трейт,
программист берёт на себя ответственность за то, что все
требования трейта выполнены. Параметров у объявления трейта нет -
он лишь помечает набор методов как потенциально опасный для
реализации.
Основное отличие небезопасного трейта от небезопасной функции
заключается в том, что ключевое слово unsafe относится
к реализации трейта, а не к его вызову. Это означает, что
вызывать методы такого трейта можно в обычном безопасном коде,
но реализовывать его разрешено только внутри блока unsafe impl.
Синтаксис
unsafe trait TraitName
{
// methods
}
unsafe impl TraitName for TypeName
{
// implementations
}
Пример
Давайте объявим небезопасный трейт UnsafeMarker
и реализуем его для структуры MyType:
unsafe trait UnsafeMarker
{
fn describe(&self) -> String;
}
struct MyType
{
value: i32,
}
unsafe impl UnsafeMarker for MyType
{
fn describe(&self) -> String
{
format!("MyType with value {}", self.value)
}
}
fn main()
{
let obj = MyType { value: 42 };
let res = obj.describe();
println!("{}", res);
}
Результат выполнения кода:
"MyType with value 42"
Пример
Рассмотрим более практичный пример: небезопасный трейт
RawBytes, который обязует тип иметь корректное
представление в памяти. Реализация помечена как unsafe impl:
unsafe trait RawBytes
{
fn as_bytes(&self) -> &[u8];
}
struct Packet
{
data: [u8; 4],
}
unsafe impl RawBytes for Packet
{
fn as_bytes(&self) -> &[u8]
{
&self.data
}
}
fn main()
{
let packet = Packet { data: [1, 2, 3, 4] };
let res = packet.as_bytes();
println!("{:?}", res);
}
Результат выполнения кода:
[1, 2, 3, 4]
Пример
Небезопасный трейт может также требовать реализации небезопасных методов. Давайте объявим трейт с небезопасным методом и реализуем его:
unsafe trait UnsafeOps
{
unsafe fn raw_double(&self, ptr: *const i32) -> i32;
}
struct Doubler;
unsafe impl UnsafeOps for Doubler
{
unsafe fn raw_double(&self, ptr: *const i32) -> i32
{
(*ptr) * 2
}
}
fn main()
{
let doubler = Doubler;
let value: i32 = 21;
let res = unsafe { doubler.raw_double(&value) };
println!("{}", res);
}
Результат выполнения кода:
42
Смотрите также
-
ключевое слово
unsafe,
которое открывает блок небезопасного кода -
unsafe fn,
которая объявляет небезопасную функцию -
unsafe impl,
которая реализует небезопасный трейт -
transmute,
которая небезопасно преобразует тип одного значения в другой