#[no_mangle]
pub fn test() {
// Вот тут на стеке выделено 4 байта
let mut idx: i32 = 10;
// Указатель на эти 4 байта
let ptr = &mut idx as *mut i32;
// По сути указатель на те же 4 байта, но на деле указатель на 40 байт
let buffer = unsafe { core::slice::from_raw_parts_mut(ptr, 10) };
// И тут мы работаем с этими 40 байтами,
// но нормальные из них только 4 байта в начале,
// а остальные смотрят в глубь стека и меняют его
// то есть перетирают адрес возврата и данные на стеке вызвавшей функции
for pixel in buffer.iter_mut() {
*pixel = 0x7d2b7500;
}
}
То есть после завершения данная функция должна не вернуться в вызывающую функцию, а передать управление непонятно куда.core::slice::from_raw_parts_mut
и метода Iterator::iter_mut
компилятор вполне может понять, что данный код не имеет сайд эффектов, а значит бесполезен и его можно вырезать. Вот собственно он его и вырезает.У переменной a указан тип встроенный массив [T; n]. Но у такого типа нет метода get_unchecked_mut(). Он есть у среза на массив [T]Тут нужно понять как в 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
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.impl<T, const N: usize> Deref for [T; N] {
type Target = [T];
fn deref(&self) -> &[T] {
// ...
}
}
За счет этого все массивы (а так же векторы, у которых тоже Deref к слайсу) получают методы слайса. И по тому же принципу String получает методы str.Что тут делает unsafe код как раз понятноОднозначно понятно, он здесь делает UB так как обращается к памяти владелец которой неизвестен.
let a = [1, 2];
let b = [3, 4];
for (a, b) in a.into_iter().zip(b.into_iter()) {
println!("{a}, {b}");
}
temp = temp.into_iter().rev().collect();
(0..cols).for_each(|col| vec[row][col] = temp[col]);
temp
владеет некоторой памятью(0..cols).for_each
итерирует и вызывает переданную ему функцию cols раз|col| vec[row][col] = temp[col]
, а так как temp захвачен замыканием по значению (по сути он является частью замыкания), то в конце итерации цикла внутри for_each еще и само замыкание дропается.index out of bounds: the len is 2 but the index is 2Это не ошибка компиляции, а runtime panic, которая говорит о там, что Вы вышли за границу слайса
while (0..rows).map(|r| vec[r].first().unwrap()).all(|&x| x == 0) {
(0..rows).for_each(|r| {vec[r].remove(0);});
};
Насколько критичной проблемой для программиста является ручное управление памятью, которое называют недостатком языка Си?Неосвобожденная память (утечка памяти) - это самое безобидное, что может произойти.
Новый язык программирования Раст, как заявляют, лишен этого недостатка
но разве число ошибок в программе зависит именно от наличия или отсутствия ручного управления памятьюВ Rust ручное управление памятью, как и в C и в C++, просто есть культура, что если некая структура аллоцировала память, то она ее освободит. Всякие Vec, Box и т.д. делают это в Drop. В C++ многие повседневные типы так же освобождают в деструкторе память, которую они выделили. Однако в Rust есть разделение на safe и unsafe код и для прикладного программирования safe возможностей более чем достаточно. В C++ же весь код unsafe.
разве общее число ошибок не перераспределяется на другие недостатки программыНет, не перераспределяется. Хорошая система типов действительно может избавить от многих ошибок, что в целом сделает ПО более надежным. Но надо понимать, что от всех ошибок не избавит ни что. Банальная дискоммуникация с заказчиком порождает огромное число багов.
являются ли ошибки с памятью ошибками программиста, а не компилятора и языка программированияБезусловно это ошибки программиста. Программисты, как правило, - это люди, а людям свойственно ошибаться. И хорошо, когда есть средства статического анализа, которые помогают предотвращать ошибки до выхода ПО в продакшн.
macro_rules! low_high_wait {
(low) => {
led.set_low().unwrap();
};
(high) => {
led.set_high().unwrap();
};
(wait) => {
block!(timer.wait()).unwrap();
};
(low, $($rest:tt),+) => {
low_high_wait!(low);
low_high_wait!($($rest),+);
};
(high, $($rest:tt),+) => {
low_high_wait!(high);
low_high_wait!($($rest),+);
};
(wait, $($rest:tt),+) => {
low_high_wait!(wait);
low_high_wait!($($rest),+);
};
}
for _ in 0..24 {
low_high_wait!(wait, high, low, low, wait);
}
for _ in 0..24 {
low_high_wait!(wait, high, wait, low);
}
for _ in 0..24 {
low_high_wait!(wait, high, low, low, wait);
}
for _ in 0..24 {
low_high_wait!(wait, high, wait, low);
}
Подскажите пожалуйста какова на данный момент ситуация с RustДефицит вакансий, дефицит грамотных разработчиков. Те что есть хотят много денег.
до сих пор еще дорабатывают, вышел ли в продакшен?он "вышел в продакшен" 5-6 лет назад, а насчет доработок - этот процес вечен, ну или пока язык не забросили, ну или как с Go не уперлись в собственный говнокод
Может ли на данный момент потягаться по кол-ву библиотек в web с Golang и в машинном обучении с Python?Ну так посмотрите сами: https://crates.io/
Планируется ли что-то в ближ. год/два?https://blog.rust-lang.org/2020/09/03/Planning-202...
Что делать если размер запроса больше чем размер буфера?Читать в цикле. read вообще не гарантирует, что заполнит буфер полностью, но больше его размера он точно за раз не прочитает. А еще он возвращает
io::Result<usize>
, в котором сообщает, сколько реально байт было прочитано.1.1) Нужно будет читать пока не найдется CRLF в буфере ?Пока read не вернет
Ok(0)
, ну или ошибку. Хотя с ошибкой не все так однозначно, согласно доке может вылететь Err(io::ErrorKind::Interrupted)
при котором стоит повторить попытку чтения. Вообще CRLF будет после каждого заголовка, а когда заголовки закончатся будет 2 CRLF подряд, а потом еще может быть тело запроса, а может и не быть.1.2) для этого мне нужно пройтись по буферу и искать CRLF . если его нет то очистить буфер и продолжать читать ?нет, нужно распарсить то что пришло, куда-то сохранить, а потом продолжить чтение.
2) Как отделять один http запрос от другого ?Если у нас не keep-alive, то каждый запрос будет в отдельном соединении, но keep-alive наступает только если обе стороны прислали заголовок
Connection: keep-alive
Можете сделать по простому, и отвечать с заголовком Connection: close
, все равно в учебном проекте производительность у Вас будет никакая. Но если хотите все же заморочиться, то правило тоже не сложное - следующий запрос начинается в следующем же байте, где закончился текущий. Размер тела запроса в байтах можно узнать из заголовка Content-Length, а если его нет, то можете считать, что его значение 0.Какие задачи решают на Rustлюбые. Rust - язык общего назначения, применимый к большинству возможных задач. Rust достаточно высокоуровневый для написания на нем прикладного ПО и компилируется в достаточно эффективный машинный код, для применения в ядрах ОС, драйверах или embedded разработке. Так же Rust на сегодня имеет самый маленький размер при компиляции в wasm, что критично для использования в web. Я честно не знаю такой сферы, к которой бы не подошел Rust.
а какие на GolangGolang тоже язык общего назначения, но имеющий ряд ограничений:
Можно один заменить другим?Rust спокойно заменяет Golang в любой возможной на последнем задаче, наоборот же иногда имеем ряд ограничений.
trait Exp {
fn exp(self) -> Self;
}
impl Exp for f32 {
fn exp(self) -> Self {
<f32>::exp(self)
}
}
impl Exp for f64 {
fn exp(self) -> Self {
<f64>::exp(self)
}
}
// через блок
mod some_module {
// тут изолированное пространство имен
pub fn hello() {
println!("Hello world");
}
}
fn main() {
some_module::hello(); // Hello world
}
// подключаем модуль из файла ./some_other_module/mod.rs или ./some_other_module.rs
mod some_other_module;
// добавлю пару констант, для простоты модификации
let rows = 2;
let cols = 2;
let matrix_a = vec![1,2,3,4];
let matrix_b = vec![5,6,7,8];
let mut matrix_c = vec![0; rows * cols]; // 0 - default, rows * cols - размер (4)
for row in 0..rows {
for col in 0..cols {
let mut vec_buf = 0;
for k in 0..2 {
vec_buf = vec_buf + matrix_a[row * 2 + k] * matrix_b[k * 2 + col];
}
matrix_c[row * 2 + col] = vec_buf; // теперь должно быть все ок
// так как спокойно передаем владение существующему элементу вектора
}
}
for (i, x) in matrix_c.iter().enumerate(){
println!(" элем = {:?}, значение = {:?}", i, x);
}