@Sasha_88

Какой тип данных у переменной a?

fn main() {
    let mut a: [u8; 0] = [];
    unsafe {
        *a.get_unchecked_mut(1) = 1;
    }
}

В этом примере у массива вызывается метод get_unchecked_mut(). У переменной a указан тип встроенный массив [T; n]. Но у такого типа нет метода get_unchecked_mut(). Он есть у среза на массив [T]. То есть операция взятия элемента по индексу обращается через ссылку? Или переменная a ссылка? Это пример на неопределенное поведение, но это не важно. Спасибо
  • Вопрос задан
  • 160 просмотров
Решения вопроса 2
bingo347
@bingo347
Crazy on performance...
У переменной a указан тип встроенный массив [T; n]. Но у такого типа нет метода get_unchecked_mut(). Он есть у среза на массив [T]
Тут нужно понять как в Rust работает оператор точка.

Во-первых, мало кто пишет, но операторов точка на самом деле в Rust целых 2:
- Доступ к полю структуры/кортежа/юниона
- Вызов метода
Rust различает их по наличию круглых скобок:
struct S {
    a: i32,
    f: fn(),
}

impl S {
    fn a(&self) {}
}

let s = S { a: 0, f: || {} };
s.a; // Доступ к полю
s.a(); // Вызов метода
(s.f)(); // Вызов функции по указателю, который лежит в поле f

С доступом к полю все просто, компилятор преобразует его в смещение в памяти где это поле лежит относительно самой структуры.
А вот с вызовом метода все интереснее, Rust пытается рассахарить его в одну из следующих конструкций в следующем порядке:
S::a(s);
S::a(&s);
S::a(&mut s);
<S as Deref>::Target::a(S::deref(&s));
<S as DerefMut>::Target::a(S::deref_mut(&mut s));
<<S as Deref>::Target as Deref>::Target::a(<S as Deref>::Target::deref(S::deref(&s)));
<<S as DerefMut>::Target as DerefMut>::Target::a(<S as DerefMut>::Target::deref_mut(S::deref_mut(&mut s)));
// ...
и так пока либо не найдет вариант, который компилируется, либо пока не обнаружит что для очередного типа не реализован трейт Deref.
Подробнее можно почитать тут: https://doc.rust-lang.org/stable/nomicon/dot-opera...

У всех массивов есть Deref к слайсу, в core библиотеке прописано что-то вроде:
impl<T, const N: usize> Deref for [T; N] {
    type Target = [T];
    fn deref(&self) -> &[T] {
        // ...
    }
}
За счет этого все массивы (а так же векторы, у которых тоже Deref к слайсу) получают методы слайса. И по тому же принципу String получает методы str.

Ну и кстати, неявный вызов deref может еще происходить при взятии ссылки.

Ну и из комментов к вопросу:
Что тут делает unsafe код как раз понятно
Однозначно понятно, он здесь делает UB так как обращается к памяти владелец которой неизвестен.
Ответ написан
vabka
@vabka Куратор тега Rust
См. ответ Дмитрий Беляев
Ошибочное, но близкое предположение
Просто для массива реализован трейт AsMut.
https://doc.rust-lang.org/std/convert/trait.AsMut.html
По тому
let a_ : &mut[u8] = &mut a;
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы