The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]



Вариант для распечатки  
Пред. тема | След. тема 
Форум Разговоры, обсуждение новостей
Режим отображения отдельной подветви беседы [ Отслеживать ]

Оглавление

Выпуск языка программирования Rust 1.66, opennews (ok), 15-Дек-22, (0) [смотреть все]

Сообщения [Сортировка по времени | RSS]


283. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от Нанонимусemail (?), 18-Дек-22, 04:30 
Стоит признать, раст слишком немощьный для низкоуровневого программирования:
- Каст &[u16] в &[u8] невозможен без сторонних библиотек
- Нет литералов для null terminated string
- У половины контейнеров нет типового параметра для кастомного аллокатора, например у String
- Сконкатенировать два массива - непосильная для раста задача: нельзя написать тип [T; N + M]
Ну и так далее. Банальные вещи, которые в C++ есть давно и никто даже не задумывается, что этого вообще может не быть. Но зато в расте есть async, конечно, это намного важнее чем скастить или конкатенировать байты. Ведь это именно то, что мы хотим на низкоуровневом языке без сборщика мусора: писать асинхронный код!
Ответить | Правка | К родителю #34 | Наверх | Cообщить модератору

302. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от Прохожий (??), 18-Дек-22, 14:47 
Стоит признать, что очередной опеннетный эксперт ничего не понимает в идеологии языка в частности и в системном программировании вообще. Говоря простыми словами, сел в лужу.

Каст правильно невозможен, иначе можно получить числовое переполнение. Создатели языка стремились сократить потенциальное количество ошибок, а не приумножать их.

Какие ещё литералы, и зачем они нужны для null terminated string? Собственно, как и сами эти строки, которые есть ничто иное, как очередной костыль, придуманный когда-то от безысходности, и который приводит к куче багов с переполнением буфера.

Объединять два массива в Rust, конечно же, можно, только делать это стоит с большой осторожностью, потому что происходит всё в куче (для динамических массивов).

Ну и так далее.

Есть такая ОС Redox. Написана полностью на Rust. Гугл недавно рапортовал, что использует Rust в ОС Android. Линус согласился принимать код на Rust. Если это не системное программирование, то что?

Ответить | Правка | Наверх | Cообщить модератору

312. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от Нанонимусemail (?), 18-Дек-22, 15:35 
> Каст правильно невозможен

Почему? В чём принципиальная проблема? Какое ещё переполнение? Что мешает при касте паниковать или возвращать Err в случае переполнения? Эта операция вполне легальна в раст, только для неё нужно подключить дополнительную библиотеку:
https://play.rust-lang.org/?version=stable&mode=debug&editio...

Вот пример того, как просто это делается. Только этого нет в std, хотя часто нужная вещь. Причём тут Redox и Linux? Можно я свой код буду на расте писать, а не ядра ОС всякие? Я говорю про свой опыт использования и уверен, много кому нужно то же самое. К чему эта неуважительная риторика про "сел в лужу"? Я стараюсь объективно взглянуть на язык, извини, что я не фанатик, как многие, кто любят раст.

Сишные литералы нужны, само собой, чтобы взаимодействовать с Сишными библиотеками. Странно, что это нужно объяснять. Сейчас в расте приходится делать Си-строку из &str, а без аллокации это невозможно, так как нет места под нулевой байт, соотвественно это вредит производительности.

>> потому что происходит всё в куче (для динамических массивов)

Я привёл пример типа [T; N + M] - что является обычным массивом, не динамическим. Опять же, странно что растер этого не понимает и путает его с Vec<T>.

Вообще, это странно выгораживать подобные недостатки языка тем, что якобы это небезопасно и вообще не нужно. Я уверен, это можно сделать и этот функционал относительно не сложен. Ну уж точно не сложнее async, но почему-то разработчики языка именно так расставили приоритеты, сделав раст труднопримениым на практике. Конечно, есть Redox, Linux и Android - только вопрос в том, сколько там unsafe? Зачем мне писать на языке, где всё что мне нужно делается через unsafe? Почему бы сразу не взять для этого unsafe язык вроде Zig или C++?

Ответить | Правка | Наверх | Cообщить модератору

332. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от freecoder (ok), 19-Дек-22, 10:43 
А почему вы не хотите взять сырые указатели и скастить их? Почему вы хотите кастить именно ссылки, для которых запрещены небезопасные операции by design?
Ответить | Правка | Наверх | Cообщить модератору

339. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от Нанонимусemail (?), 19-Дек-22, 16:20 
Можно мне объяснить, чего небезопасного в касте &[u16] в &[u8]? Я показал пример, где это делается без всякого unsafe кода. Да, внутри там всё равно unsafe, но снаружи безопасный api, как и многое в std. Что принципиально мешает так сделать?
Ответить | Правка | Наверх | Cообщить модератору

345. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от freecoder (ok), 19-Дек-22, 22:44 
> Что принципиально мешает так сделать?

Ничего не мешает. Просто всего в std не утащишь. Если у вас есть понимание, что это нужно в std и в каком именно виде оно там должно быть - создайте issue.

Ответить | Правка | Наверх | Cообщить модератору

336. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от freecoder (ok), 19-Дек-22, 13:25 
Для работы с сишными строками есть типы CString и CStr. Вы можете сконструировать CStr из байтового строкового литерала:

use std::ffi::CStr;

const MSG: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"Hello\0") };

Но это небезопасная операция (нет гарантии, что ваша последовательность байт обязательно заканчивается нулём). Но вы можете использовать простой макрос c_str чтобы избавиться от unsafe:

const MSG: &CStr = c_str!("Hello");
https://play.rust-lang.org/?version=stable&mode=debug&editio...

Да, на уровне синтаксиса языка Rust нет поддержки литералов C-строк. Но её относительно легко добавить с помощью макроса.


Ответить | Правка | К родителю #312 | Наверх | Cообщить модератору

341. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от Нанонимусemail (?), 19-Дек-22, 16:40 
Спасибо за совет. Однако, видимо с точки зрения разработчиков языка создание сишных строк настолько редкая и ненужная операция, что не то что сишные литералы отсутствуют в языке, даже подобного макроса нет в std. Не понимаю что принципиально мешает это сделать?
В итоге получается вот такой неоптимальный код при вызове сишных библиотек:
https://github.com/grovesNL/glow/blob/main/src/native.rs#L1200
Ответить | Правка | Наверх | Cообщить модератору

343. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от freecoder (ok), 19-Дек-22, 22:23 
> В итоге получается вот такой неоптимальный код при вызове сишных библиотек:
> https://github.com/grovesNL/glow/blob/main/src/native.rs#L1200

В этом месте по другому и не сделать, тут же не литерал используется, а строковый срез &str. Так что вам все равно нужно аллоцировать строку заново, чтобы добавить ещё один
символ в конце.

Ответить | Правка | Наверх | Cообщить модератору

349. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от Нанонимусemail (ok), 20-Дек-22, 11:52 
А почему авторы библиотеки решили принимать &str, а не &CStr?
Уж не потому ли, что нормальной поддержки сишных строк нет и проще сделать так?
Это пример к слову о "ненужности" си-строк. При всём моём уважении к расту и его сообществу, поддержка сишных библиотек сделана откровенно плохо. У C++ и Zig в этом плане гораздо более существенные преимущества, хотя и языки сами по себе небезопасны.
Ответить | Правка | Наверх | Cообщить модератору

356. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от freecoder (ok), 22-Дек-22, 10:23 
> А почему авторы библиотеки решили принимать &str, а не &CStr?
> Уж не потому ли, что нормальной поддержки сишных строк нет и проще сделать так?

Это уже вопрос к авторам библиотеки. Написать &CStr вместо &str не намного сложнее, не находите?

Ответить | Правка | Наверх | Cообщить модератору

357. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от freecoder (ok), 22-Дек-22, 10:29 
> Это пример к слову о "ненужности" си-строк. При всём моём уважении к
> расту и его сообществу, поддержка сишных библиотек сделана откровенно плохо. У
> C++ и Zig в этом плане гораздо более существенные преимущества, хотя
> и языки сами по себе небезопасны.

Эти вещи взаимосвязаны: многие вещи в Си (включая строки) небезопасны by design. Они плохо вписываются в подходы обеспечения безопасности в Rust. Поэтому и не поддерживаются прозрачно, чтобы их использовать нужно приложить усилия. То есть их следует использовать, если нет других альтернатив.

Ответить | Правка | К родителю #349 | Наверх | Cообщить модератору

359. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от Нанонимусemail (ok), 22-Дек-22, 12:33 
> Написать &CStr вместо &str не намного сложнее, не находите?

Написать то не сложно, только как потом пользователи библиотеки будут вызывать эти функции? Либо макрос придётся свой городить, либо делать строку из CString, ну либо CStr::from_bytes_with_nul(b"hello\0").expect("тут нул-терминейтед-стринг, я клянусь"). В общем, неудобно это, проще принимать &str.

> небезопасны by design

Тогда интересно, в чём именно их небезопасность? Растовый тип CStr столь же безопасный как и другие типы, с учётом отдельных unsafe методов которые так же есть и у родных растовых строк. Или компилятор не в состоянии проверить инвариант литерала строки, например чтобы в середине не было нулевых байт? При этом проверять валидность utf-8 он прекрасно может

Ответить | Правка | Наверх | Cообщить модератору

360. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от freecoder (ok), 23-Дек-22, 10:40 
Я думаю авторы библиотеки рассчитывали, что пользователи в своем коде будут оперировать динамическими Rust-строками, поэтому при вызове сишной функции всё равно нужно будет делать новую аллокацию. Эта проблема не связана с отсутствием синтаксиса для литералов сишных строк, она скорее о том "почему в Rust по-умолчанию принято использовать строки не такие как в Си".
Ответить | Правка | Наверх | Cообщить модератору

361. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от freecoder (ok), 23-Дек-22, 19:48 
Кстати, есть RFC и issue для добавления сишных строковых литералов: https://github.com/rust-lang/rust/issues/105723
Ответить | Правка | К родителю #359 | Наверх | Cообщить модератору

328. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от Проходил мимо (?), 19-Дек-22, 08:16 
Мне вот недавно потребовалось выделить под буфер кусок динамической памяти, размер которого не известен на стадии компиляции. То, что в Си элементарно делается при помощи malloc() а в Си++ при помощи new. И знаете, я был в шоке, когда погрузился в подробности этого процесса в Rust и выяснил, что просто так это сделать невозможно. Мы можем выделить только массив, размер которого известен на этапе компиляции. Это 3.14сец, товарищи. В итоге я вынужден был использовать вектор с unsafe блоком для принудительного изменения его длины. Можно было также использовать другой костыль Vec::as_mut_slice() но это те же яйца, только сбоку. Не будет ли любезен претендующий на понимание идеологии и системного программирования уважаемый джинн ответить, какого хера для реализации одной из повсеместно используемых базовых операций нужны такие танцы с бубном?
Ответить | Правка | К родителю #302 | Наверх | Cообщить модератору

335. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от freecoder (ok), 19-Дек-22, 12:50 
В Rust можно динамически выделять память руками, просто нужно иметь ввиду, что придется самому определить лайаут, скастить указатели и обеспечить инициализацию памяти. Это unsafe операции, так что тут ответственность ложится на плечи программиста:

use std::{alloc::{alloc, Layout}, slice};

fn main() {
    let n = 1000;
    let a = unsafe {
        let layout = Layout::array::<i32>(n).expect("Layout overflow");
        let ptr = alloc(layout) as *mut i32;

        ptr.write_bytes(0, n);
        slice::from_raw_parts(ptr, n)
    };
    
    println!("{a:?}");
}

https://play.rust-lang.org/?version=stable&mode=debug&editio...
Ответить | Правка | Наверх | Cообщить модератору

338. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от Проходил мимо (?), 19-Дек-22, 15:38 
>[оверквотинг удален]
>         let layout = Layout::array::<i32>(n).expect("Layout
> overflow");
>         let ptr = alloc(layout)
> as *mut i32;
>         ptr.write_bytes(0, n);
>         slice::from_raw_parts(ptr, n)
>     };
>     println!("{a:?}");
> }
> https://play.rust-lang.org/?version=stable&mode=debug&editio...

Да, подобный костыль тоже возможен, но то, что это все вообще требуется говорит о том, что далеко не все там продумано должным образом. Ибо операция выделения буфера произвольного размера в реальном низкоуровневом коде встречается настолько часто, что средство для этого просто обязано быть простым и понятным. Нужно что-то типа fn  alloc_slice(size: usize) -> Option<Box[u8]> и это что-то должно быть в стандартной библиотеке а не делаться на коленке в с применением unsafe блоков

Ответить | Правка | Наверх | Cообщить модератору

344. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от freecoder (ok), 19-Дек-22, 22:36 
> Нужно что-то типа fn  alloc_slice(size: usize) -> Option<Box[u8]>

Если вам нужен Box<[u8]>, то делайте так:


vec![0; n].into_boxed_slice()

Ответить | Правка | Наверх | Cообщить модератору

340. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от Нанонимусemail (?), 19-Дек-22, 16:31 
А почему бы не выделить нужную память вектором Vec<u8> или Box<[u8]>?
Ответить | Правка | К родителю #328 | Наверх | Cообщить модератору

348. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от Проходил мимо (?), 20-Дек-22, 07:27 
> А почему бы не выделить нужную память вектором Vec<u8> или Box<[u8]>?

Выше написано, что я так и сделал. Но, в данном случае, это лишняя сущность, которую мы плодим без надобности. Собственно, чтобы было более понятно, вот текущий код:


    fn  read_data_block(&mut self)-> Option<usize>
    {
        let mut r : Option<usize> = None;
        //  Флаг повторного считывания даных в случае, если функция была
        //  прервана сигналом (ErrorKind::Interrupted)
        let mut read_flag = true;

        while   read_flag
        {
            //  Мы используем внутренний буфер вектора как мутабельный слайс
            match   self.data_src.read(&mut self.buf.as_mut_slice())
            {
                //  В случае успеха возвращает количество считанных байт
                Ok(n)  =>
                {
                    //  Повторное считывание не требуется
                    read_flag = false;
                    //  Установим новое количество байт в векторе, так как
                    //  он сам ничего не знает о том, что в него были
                    //  считаны данные извне
                    //  Эта операция считается небезопасной, поэтому
                    //  используем unsafe блок
                    unsafe
                    {
                        self.buf.set_len(n);
                    }
                    //  Подготовим возвращаемый результат
                    if n > 0 { r = Some( n ); }
                },
                Err(e) =>
                {
                    if e.kind() != ErrorKind::Interrupted
                    {
                        read_flag = false;
                        self.io_error = Some( e.kind() );
                    }
                }
            }
        }
        //  Вернем результат считывания
        r
    }


Он требует доработки, чтобы еще была правильно обработана ошибка обрыва Пипы, но, в целом, вполне рабочая.
Ответить | Правка | Наверх | Cообщить модератору

350. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от Нанонимусemail (ok), 20-Дек-22, 12:15 
А для чего тут self.buf.set_len(n)?
Можно после прочтнения в буффер взять слайс у &self.buf[..n] и получится то же самое, только без unsafe. Если нужно получать как результат именно Vec<u8>, можно позвать безопасный метод self.buf.resize(n, 0) или self.buf.truncate(n) который сделает то же самое что и unsafe аналог.

Ещё у трейта Read есть вспомогательные методы, например read_exact
https://doc.rust-lang.org/std/io/trait.Read.html#method.read...
Которые игнорируют ErrorKind::Interrupted и продолжают читать дальше. Возможно, в вашем случае один из подобных вспомогательных методов упростил бы код

Ответить | Правка | Наверх | Cообщить модератору

358. "Выпуск языка программирования Rust 1.66"  +/
Сообщение от freecoder (ok), 22-Дек-22, 10:56 
А что будет делать ваш код, если self.buf будет нулевой длины?

Вот вариант блочного чтения без unsafe:


fn read_data_block(&mut self) -> Option<usize> {
    let mut bytes_read = 0;
    let mut buf = self.buf.as_mut_slice();

    while !buf.is_empty() {
        match self.data_src.read(buf) {
            Ok(0) => break,
            Ok(n) => {
                bytes_read += n;
                buf = &mut buf[n..];
            }
            Err(err) => if err.kind() != ErrorKind::Interrupted {
                self.io_error = Some(err.kind());
                break;
            }
        }
    }
    
    self.buf.truncate(bytes_read);
    if bytes_read > 0 { Some(bytes_read) } else { None }
}


Только нужно помнить, что до вызова этого метода self.buf должен иметь нужный вам размер.
Ответить | Правка | К родителю #348 | Наверх | Cообщить модератору

Архив | Удалить

Рекомендовать для помещения в FAQ | Индекс форумов | Темы | Пред. тема | След. тема




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру