Comments 17
Советую всем к ознакомлению с серией статей от Энтони Фу
https://antfu.me/posts/ai-qrcode
Касаемо статьи: много return
, которые можно опустить.
// Зачем нужна эта функция?
fn create_reed_solomon_encoder(num_error_correction_blocks: usize) -> Encoder {
let reed_encoder: Encoder = Encoder::new(num_error_correction_blocks);
return reed_encoder;
}
impl Iterator for ZigZagIt {
type Item = (usize, usize);
fn next(&mut self) -> Option<Self::Item> {
if !self.valid { return None; }
let cordinates: (usize, usize) = (self.row_cordinate, self.column_cordinate);
self.move_cordinate();
// Зачем return?
return Some(cordinates);
}
}
Если необходимо было освоиться в Rust, то считаю, что лучшим решением было бы написать крейт с нуля
Спасибо за комментарий! В моём коде я хотел правильно делить функции, но я кажется перестарался. Return же я просто привык писать, но кажется стоить себя переучивать. В следующий раз я исправлю эти недочёты.
Про создание своего крейта, Вы это про алгоритм Рида Соломона?
В том числе. Это был бы очень хороший опыт
Ещё б неплохо почитать про match
и про DRY.
Пелёнка превращается
fn generate_bitvec(integer: u32) -> BitVec {
let bit_len = |num: u32| {
if num > 99 {
return 10;
}
else if num > 9 {
return 7;
}
else {
return 4;
}
};
let mut bitvector: BitVec = BitVec::new();
bitvector.reserve(bit_len(integer));
append_to_bitvec(&mut bitvector, &integer, bit_len(integer));
return bitvector;
}
В элегентную функцию
fn generate_bitvec(num: u32) -> BitVec {
let bit_len = match num {
_ if num > 99 => 10,
_ if num > 9 => 7,
_ => 4,
};
let mut bitvector = BitVec::with_capacity(bit_len);
append_to_bitvec(&mut bitvector, &integer, bit_len);
bitvector
}
А мне нравится писать return в rust)
А можно ссылку на пионир?
Да, конечно: https://pionir.org. Это Сербская школа которая обучает нас, в основном с помощью практики. Мы много чем занимаемся, и пытаемся улучшить окружение око нас.
Сайт чуть-чуть не информативен, поэтому разрешите задать вопрос: со скольки и до скольки лет принимаются заявки? Сайт на сербском без возможности выбора языка, значит ли это то, что нужно знать сербский? На каком языке говорят в вашем чате?
И, как я понял из обрывков информации, там кроме программирования ещё проектируют устройства на печатных платах?
Да, сайт и правда не информативен, так-как староват, мы сейчас создаём новый.
Пока что здесь принимаются дети которые знают Сербский и Английский, но если что, здесь есть люди которые говорят на нескольких языках, например наш директор знает Русский.
Заявки же принимаются с 13 до 17 лет, но с идеей что ученики останутся и дальше в школе.
Кроме программирования мы много чем занимаемся, например: электроника, дизайн, этика, право, социология, экономия, и даже садоводство в каком-то смысле, всё это учится вместе, интегрировано в остальные моменты. Но ученик сам выбирает свою сферу обучения, по своему желанию и возможностям.
Надеюсь это немного прояснило про нашу школу.
А мне нравится этот язык. Читабельность у него ниже, чем у Java, но зато он потенциальный заменитель C/C++. Если ещё сделают грамотную обработку исключений в нём, чтобы не было таких баг вроде "На 40-ой минуте звонка стабильно у абонентов пропадает звук", из-за того, что переменная переполнилась и обнулилась, то будет совсем замечательно. И Race Condition под нагрузкой с битьём памяти самый ад, или разная работа программы на разных девайсах. Или уязвимости. Если всё это смогут сделать, то C/C++ окончательно отправятся на пенсию и будут там сидеть вместе с языком Ada,Fortran-ом и Cobol-ом.
Для того, чтобы ещё лучше понять, что происходит на низком уровне, я бы порекомендовал хорошенько разобраться в C. Не в C++ (это плохой язык), а именно в С. Этот язык прост в синтаксических конструкциях, но очень сложен в написании отказоустойчивого кода. Нужно очень серьёзное понимание компьютера, чтобы успешно писать на нём. Несколько мощных выстрелов себе в ногу как раз и помогут понять, зачем был создан Rust, зачем нужно и очень полезно испытывать боль от Borrow checker'а, зачем все эти церемониальные практики языка.
Понимаю, что это, возможно, первый код автора на Rust, но всё-таки хочется указать на некоторые недочёты.
Непонятен выбор библиотек. Почему generic-matrix
вместо ndarray или nalgebra? Почему именно reed-solomon
? Так вышло, что я знаком с автором reed-solomon
, и он говорит, что эта библиотека была в своё время его упражнением в Rust и не предназначена для серьёзного использования.
Теперь непосредственно по коду.
impl Module { pub fn set_module(&mut self, new_module: Module) { *self = new_module; }
Этот метод просто не нужен и целиком заменяется на оператор присваивания по месту.
pub fn is_fun(&self) -> bool { match self { Module::Function(_) => return true, _ => return false, } }
Можно написать короче:
pub fn is_fun(&self) -> bool {
matches!(self, Self::Function(..))
}
pub fn flip_module(&mut self) { match self { Self::Data(true) => *self = Self::Data(false), Self::Data(false) => *self = Self::Data(true), _ => (), } }
Опять-таки, можно написать короче и заодно не расписывать все варианты:
pub fn flip_module(&mut self) {
if let Self::Data(data) = self {
*data = !*data;
}
}
pub fn set_square(&mut self, size: usize, cordinate: (usize, usize), matrix_module: &mut Matrix<Module>) { let start_width: usize = cordinate.1; let start_height: usize = cordinate.0; for i in 0..size { for j in 0..size { let new_module = matrix_module.index_mut((i, j)); self.set_module((i + start_height, j + start_width), *new_module); } } } pub fn set_module(&mut self, cordinate: (usize, usize), new_module: Module) { let mut _module: &mut Module = self.get_mut_module(cordinate); _module.set_module(new_module); }
К этим функциям у меня хватает вопросов:
- Зачем отдельным параметром передается
size
, если, насколько я понимаю, можно вынуть размер изmatrix_module
? - Зачем
matrix_module
передаётся по мутабельной ссылке, если он не меняется? - Зачем используется
index_mut
вместо оператора индексации? - Почему в
set_module
выносится отдельная переменная_module
, да ещё и с прочерком в начале? В Rust так принято именовать неиспользуемые переменные, поскольку по умолчанию на них не срабатывает предупреждение о мёртвом коде.
(и, кстати, почему cordinate
с одной o
?)
И да, библиотеки рулят. С какой-нибудь nalgebra
весь метод можно было бы свести к
pub fn set_square(&mut self, at: (usize, usize), square: &DMatrix<Module>) {
self.module.view_mut(at, square.shape()).copy_from(square);
}
Далее, функцию create_reed_solomon_encoder
можно без ущерба для кода заменить на Encoder::new
. Это даже короче.
pub fn create_error_corrections_blocks(data: Vec<u8>, num_error_correction_blocks: usize) -> Vec<u8> { let reed_encoder: Encoder = Self::create_reed_solomon_encoder(num_error_correction_blocks); let data_copy = reed_encoder.encode(&data).to_vec(); return data_copy; }
Разнесено на три строчки то, что можно уместить в одну:
pub fn create_error_corrections_blocks(data: &[u8], num_error_correction_blocks: usize) -> Vec<u8> {
Encoder::new(num_error_correction_blocks).encode(data).to_vec()
}
И да, функция зачем-то принимает на вход Vec<u8>
, вынуждая вызывающую сторону безусловно выделять память, в то время как просто слайса (&[u8]
) было бы достаточно (собственно, это именно то, что принимает на вход Encoder::encode
).
В функции move_horizontaly
есть число 6. Мне, как человеку со стороны, вообще непонятно, откуда оно взялось.
В функции move_vertical
есть вот такой странный фрагмент:
else { if self.upward { self.row_cordinate -= 1 } else if !self.upward { self.row_cordinate += 1 } self.column_cordinate += 1; }
Зачем тут else if
? Условия self.upward
и !self.upward
взаимно исключают друг друга.
В любом случае, не смотря на недочёты, видно, что автор программировать всё же умеет — что правда впечатляет с учётом его возраста. Правда, у меня сложилось впечатление, что хоть это и первая программа на Rust, но не первый опыт программирования у автора в принципе. Судя по косвенным признакам (аннотации типов, геттеры, сеттеры, ненужные return
), я бы сделал ставку на Java. Я угадал?
И да, хотелось бы увидеть опубликованный код, желательно на платформе, где можно предложить исправления. Кода в статье не хватает для того, чтобы собрать программу целиком.
Большое спасибо за такой подробный комментарий!
>>Непонятен выбор библиотек. Почему generic-matrix
вместо ndarray или nalgebra? Почему именно reed-solomon
? Так вышло, что я знаком с автором reed-solomon
, и он говорит, что эта библиотека была в своё время его упражнением в Rust и не предназначена для серьёзного использования.
Так-как я только начал программировать на Rust, я достаточно небрежно выбирал библиотеки, в следующий раз я буду смотреть более детально.
>>Опять-таки, можно написать короче и заодно не расписывать все варианты:
Я видел разные фишки, как сделать код в Rust более коротким, и так код выглядит намного лучше, за следующий проект я сделаю код лучше и читабельнее чем сейчас.
Про функции set_square
, size
действительно не нужен, я его просто забыл удалить, так-как в первой версии кода не было matrix_module
, также у matrix_module
мутабельная ссылка из-за той же причины.
Самая большая проблема была в том, что я не знал как будет выглядит архитектура всего кода, поэтому я часто всё менял, забывая что-то исправлять(хотя работает всё исправно).cordinate
, здесь просто моя невнимательность, исправлю когда дойдут руки.
>>>И да, библиотеки рулят. С какой-нибудь nalgebra
весь метод можно было бы свести к
pub fn set_square(&mut self, at: (usize, usize), square: &DMatrix<Module>) {
self.module.view_mut(at, square.shape()).copy_from(square);
}
Спасибо за библиотеку, скорее всего она будет очень полезна в следующих проектах.
>>В функции move_horizontaly
есть число 6. Мне, как человеку со стороны, вообще непонятно, откуда оно взялось.
Да, я понимаю что в моём коде многовато магических чисел, в этом случае, столбец под номером "6" имеет все функциональные блоки, так-что его надо всего лишь обойти.
Я не особо хорош пока что в наименованиях, поэтому я оставил так, в QR кодах есть много разных таких чисел, которые были выбраны создателями QR кода, но наименование тяжело выбрать.
И да, я правда много программировал и до Rust-а, но в основном на Python и C#, хотя на C# я программировал очень мало, но привычки остались.
Вот мой GitHub, там можете посмотреть мои проекты на Python и целый код генератора. Там не все мои проекты, я занимался много чем, но не всё выставлял в GitHub.
Мне 15 лет и я написал QR код генератор на Rust