У переменной 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 так как обращается к памяти владелец которой неизвестен.