Как стать автором
Обновить
236
0
Павел @Riateche

Пользователь

Отправить сообщение
Ниже написал про &mut str. Потребоваться он может, когда нужно позаимствовать строку или часть строки и изменить ее. Проблема в том, что существует не так много изменяющих операций с строками в UTF-8, которые не меняют их длину.
А вы посмотрите на реализацию этого метода:
fn make_ascii_uppercase(&mut self) {
  let me: &mut [u8] = unsafe { mem::transmute(self) };
  me.make_ascii_uppercase()
}

Т.е. на самом деле для этого необходимо преобразовать в &mut [u8]. Напрямую поменять что-то в &mut str действительно нельзя, просто нет методов для этого. Это из-за того, что нельзя менять количество байтов в позаимствованной строке (она вполне может быть подстрокой другой строки), а редактирование UTF-8 в общем случае может менять количество байтов практически при любой операции.

Тем не менее, &mut str — не то же самое, что &str, потому что &str в &mut [u8] преобразовать сложнее. Так что и тут mut вполне означает изменяемость.
Про Rust
> borrowck отвергает безопасный код.

Очевидно, что автоматически понять, является ли программа безопасной и корректной, в общем случае невозможно. Safe-подмножество Rust разрешает лишь подмножество безопасных программ. Поэтому глупо жаловаться, что borrow checker «отвергает безопасный код». Конечно, хочется, чтобы язык позволял более широкий спектр безопасных программ, но никогда не будет такого языка, который отвергает весь опасный код и принимает весь безопасный.

> В конце концов, «небезопасный» блок не говорит, что содержание блока вызовет неопределённое поведение

Естественно. Safe Rust в идеале гарантирует отсутствие неопределенного поведения, но обратное неверно. Если бы процитированное утверждение было неверно, то это была бы очень комичная ситуация — специальное ключевое слово, чтобы писать только некорректный код.

> это означает, что содержание небезопасного блока было ошибочно отклонено компилятором.

За исключением багов компилятора, нельзя здесь говорить об ошибочности. Ограничения safe Rust задокументированы. Опять же, никто не обещал, что он примет любую программу, которую можно считать корректной.

> borrowck, всё же, имеется, даже когда вы находитесь внутри unsafe {} блока или функции

Но там с ним можно легко расправиться, если использовать указатели вместо ссылок.

> чтобы сотворить, действительно, волшебство, необходимо дать вызов, содержащий некоторые многословные имена вроде sliceable.unsafe_get(index).

В стандартной библиотеке нет unsafe_get. Если имеется в виду get_unchecked, то он используется для получения элемента массива без проверок на границы индексов и к borrow checker не имеет отношения.

> Никто не знает, какие правила определяют опасность.
> Это означает, что содержимое небезопасного блока является трудным для чтения, что оно по определению является слишком сложным, чтобы быть очевидно правильным, что оно нечётко задано и должно быть написано на коде низшего уровня.

Писать unsafe-код корректно в Rust действительно сложно. В Rustonomicon об этом хорошо написано.

Зато известно, какие правила определяют «безопасность» в терминах Rust. Эти правила компилятор проверяет и не даст вам ошибиться. Так что писать на безопасном подмножестве можно вполне спокойно.

> У Rust есть исключения. Он называет их тревожными и редко использует их, но у него они есть, и ваш небезопасный код должен быть транзакционным в отношении безопасности памяти. До сих пор они имели примерно такой же успех, последовательно соблюдая это, какой имели разработчики в C++ (за исключением тех разработчиков в C++, которые запрещают исключения, как, например, Google).

Непонятно, в чем проблема. На C++ можно писать код, безопасный по отношению к исключениям, и в Rust ничуть не меньше средств для этого.

> Таким образом, «безопасность» Rust позволяет делать существенно меньше ошибок в чрезвычайно простых кодах, но не помогает в сколько-нибудь сложных.

Rust не защитит от логических ошибок, которые свойственны большим программам, но по крайней мере, у вас не будет в них сегфолтов и конкурентного доступа к непотокобезопасным данным. Это очень помогает на практике.

> Точки с запятой и неприятный синтаксис :: получены в наследство от С++. Также унаследован ещё более безобразный шаблонный/универсальный синтаксис.

Дело вкуса.

> Обе эти функции осуществляют проверку и не возвращают предупреждений, но делают весьма различающиеся операции.

Эти функции делают одно и то же, только одна возвращает результат последнего выражения, а другая нет. Для тех, кто знаком с синтаксисом, нет ничего неочевидного. Если бы вы так попытались сделать с типом Result, то компилятор выдал бы вам предупреждение, не позволив просто так забыть обработать ошибку.

> Чрезмерно кратко поименованные типы и ключевые слова, которые не передают их назначение, как, например, impl и ().

Плохие примеры. «impl» — сокращение от «implement», и код вида «impl MyStruct» или «impl MyTrait for MyStruct» читаются очевидным образом. () — пустой кортеж, частный случай синтаксиса (T1, T2, ...). В чем тут проблема, непонятно. Я бы лучше поругался на ключевое слово type, которое мешает называть этим словом переменные и функции.

> mut означает исключительный, а не изменчивый (mutable).

Нет, «mut» означает «изменяемый». Например, «let mut x = 1;» — декларация изменяемой переменной (без mut была бы константная). В ссылках "&mut x" также означает «изменяемый», а исключительность уже следует из правил Rust.

> &Mutex означает изменчивый (mutable)

Mutex и RefCell являются в некотором роде исключениями. Использование этих типов говорит, что мы можем безопасно изменять один и тот же объект из нескольких мест. Имея &Mutex, вы можете получить из него &mut T и изменить объект, но сам Mutex передается по константной ссылке (&, а не &mut), создавая иллюзию, что объект неизменяем. Сделано так потому, что borrow checker просто не разрешит создать несколько неконстантных ссылок на один и тот же объект. Выглядит не очень очевидно, но не так уж и страшно.

> а &mut str — неизменяемый (immutable).

Да, тип str вообще особенный и вносит много путаницы.

> Чрезмерно кратко поименованные типы и ключевые слова, которые не передают их назначение, как, например, Vec и Cell.

Дело вкуса. При желании можно переименовать тип при импортировании.

> Большинство думает, что Rust имеет два типа строк…

Нет ничего плохого в том, чтобы разграничить разные типы строк. String — строка в utf-8. CString — нуль-терминированная строка в произвольной кодировке (прямо как в C). OsString — строка в формате, используемом в нативном API текущей ОС. С преобразованиями между этими типами проблем нет, везде есть соответствующие методы. Ну, а &str, &CStr и &OsStr — это позаимствованные строки в соответствующих форматах.

> Повсеместное неявное преобразование (типа) означает, что справочные документы практически бесполезны. Можно взять Vec, поскольку он неявным образом преобразует в &[T], например, и можно использовать для циклов с Vec и &[T], но результат будет немного различающимся в зависимости от того, что используется.

Видимо, имеется в виду Deref. Во-первых, реализованный Deref описывается в документации типа. Во-вторых, не Vec, а &Vec автоматически преобразовывается к &[T]. И результат итерирования по &Vec и &[T] будет одинаковым. А если итерироваться по Vec, то результат, конечно, будет другой (вектор будет разрушен). А вот Vec к &Vec автоматически преобразовываться не будет.

> Не совсем повсеместное преобразование (типа) означает, что ваш код оказывается замусоренным тарабарщиной вроде &*some_var (который преобразует интеллектуальный указатель в ссылку) и &some_var[..] (это — та самая магическая формула, которая преобразует Vec в &[T] или String в &str).

Неправда. Благодаря упомянутому выше Deref можно писать просто &some_var в обоих случаях.

> Дублирующие элементы, такие как, например, структуры кортежа и модулеподобные структуры

Tuple-structs позволяют делать структуры без именования полей, что вполне может быть осмысленно в некоторых случаях. Unit-like structs (структуры без полей) используются для построения API, например, чтобы выразить глобальный ресурс, захваченный мьютексом (часто используется в обертках сишных библиотек).

> Типы суммы — не enum. Хватит притворяться С.

Согласен, называть tagged union enum-ом — решение плохое.

> Поскольку он статически связывает всё (спасибо, Go, за выпуск этой модной штучки), вы получите тысячи, вероятно, устаревших копий кольца на вашем компьютере.

Можно делать динамическую линковку, если кому-то хочется.

> Действительно, он статически связывает почти всё. Он динамически связывает вашу программу с библиотекой, в результате чего ваши исполняемые файлы не являются, на самом деле, самодостаточными.

В оригинале имеется в виду динамическая линковка с libc. Делать это статически — вещь весьма специфическая.

> Нет пространства имён в поставке. Всё получает «креативные» имена, как, например, «ring» (набор криптопримитивов) или «serde» («serialization and deserialization» («сериализация и десериализация»), ничего?).

Согласен. В копилку: «select» — интерфейс к HTML-парсеру.

> Обобщённые типы очень распространены, и они по существу копируются и вставляются для каждого конкретного типа, с которым они используются (спасибо тебе, С++, что сделал это популярным). Вы знаете то, что делает компиляцию по сути тем же самым кодом часто ещё более болезненной?

Какие альтернативы предлагаете?

> rustc работает медленно…

Претензии к медленной компиляции, нехватке поддерживаемых платформ, отсутствию инкрементальной компиляции (кстати, в nightly ее уже начали внедрять) и хорошей IDE справедливы, но временны. Язык еще очень молодой.

> Не первый раз такое читаю, но логичного объяснения никто не даёт,

Во-первых, это почти всегда бессмысленно. Если кто-то скачивает исходный код вашего проекта, то он это делает для того, чтобы скомпилировать его из этих исходных кодов. В этом случае артефакты сборки ему совершенно не нужны. Если кому-то нужен exe-файл, то ему при этом не нужны исходники. Для выкладывания готовых файлов на github есть Releases. Кроме того, часто для работы exe-файлы нужны всякие dll-файлы зависимостей (правда, некоторые могут и эти dll в репозиторий добавить). Ну, а объектные файлы почти наверняка никому не пригодятся.

К тому же сборочные файлы могут зависеть от ОС и окружения и могут даже вызвать проблемы со сборкой (файл не пересобирается, потому что он уже есть, но его не получается использовать, т.к. его формат несовместим с текущим окружением).

Во-вторых, это раздувает объем репозитория и заставляет тех, кто работает с вашим кодом, скачивать ненужные им файлы. Размеры exe-файлов в дебажных сборках запросто достигают десятков мегабайт, а ведь система контроля версий будет хранить все закоммиченные версии этих файлов, и репозиторий быстро вырастет до ужасных размеров.

В-третьих, бинарные файлы будут изменяться с каждым изменением кода и будут засорять историю изменений, ради которой система контроля версий и затевается. Хочется, глядя на коммит, быстро увидеть, какие файлы в нем изменились, и постоянные бессмысленные изменения бинарных файлов в каждом коммите будут очень мешать.
Можно просто bottom менять: https://jsfiddle.net/qw5h82qp/7/
Есть несколько замечаний.

Результаты компиляции (*.o, *.exe) в систему контроля версий класть не следует.

Зависимость от Codeblocks — это неудобно. Можно использовать CMake в качестве системы сборки. Он более распространен и его проще поставить. CMake сможет сгенерировать проектные файлы и для CodeBlocks, и для VS, а также Makefile для многих ОС и окружений.

Имеет смысл сделать опции для указания пути к генерируемому файлу и для вывода результата генерации прямо в stdout.
> Вот зачем это нужно было делать? Чтобы всех запутать?

Конечно, нет. На это тоже есть исторические причины. Подробнее можно прочитать здесь. Латинскими буквами обозначаются ноты, соответствующие белым клавишам. Сначала нотации для черных нот вообще не было. Первой появилась необходимость нотации для ноты си-бемоль. Чтобы различать си и си-бемоль, их начали писать в разных начертаниях: си-бемоль — в латинском (b), а си — в готическом, с острыми углами. В некоторых частях Европы готическое начертание B преобразовалось в H — то ли из-за визуального сходства, то ли из-за немецкого слова hart. Позднее разные начертания B преобразовались в бемоль (b -> ♭) и бекар (♮), которые можно применять ко всем нотам.

Так что я бы не стал винить в ситуации тех, кто решил писать H. Скорее уж тех, кто решил использовать готическое написание той же буквы.
Еще существует консольный калькулятор apcalc.
Особенно при отсутствующих заголовках статей.
Мне кажется, что существенный недостаток сегвеев и моноколес — необходимость ехать стоя. Всю дорогу стоять на месте, еще и при необходимости переносить вес вперед или назад (т.е. нельзя встать в наиболее удобную позу или просто сменить ее, как при езде в автобусе) — вещь не самая приятная. Не представляю, как этим можно заниматься ежедневно (например, по дороге на работу и обратно). Идти пешком намного проще, не говоря уже о езде на велосипеде. Интересно узнать мнение тех, кто ездит на моноколесах.
Я просто не понимаю, как так получается, что у вас аккаунт не голосующий, а на скриншоте стрелки подсвеченные, что показывает, как проголосовал текущий пользователь.
А скриншот откуда?
Как же так — «большое спасибо за вопрос», а комментарию минус поставили, судя по скриншоту.
Со всеми пунктами, кроме 2, хорошо справляется оффлайновый 2gis.
Статически типизированные языки ограничивают типы переменных: язык программирования может знать, например, что x — это Integer. В этом случае программисту запрещается делать x = true, это будет некорректный код. Компилятор откажется компилировать его, так что мы не сможем даже запустить такой код.
Но ведь для статических языков со слабой типизацией это может быть неверно. Всё зависит от наличия приведения типов.

Однако, в большинстве статически типизированных языков выражение «a» + 1 — это не программа: она не будет скомпилирована и не будет запущена. Это некорректный код, так же, как набор случайных символов !&%^@*&%^@* — это некорректный код.
Это слишком радикальное утверждение. Обычно процесс компиляции состоит из нескольких этапов. Если код проходит этапы лексического и синтаксического анализа и позволяет компилятору провести проверку типов, то он намного ближе к корректной программе, чем набор случайных символов. Конечно, с точки зрения пользователя это несущественная разница (и то, и то не компилируется), но с точки зрения компилятора разница есть.

Ну и опять же, компилируемость «a» + 1 зависит не от того, статическая или динамическая типизация в языке, а от того, есть ли в нем неявное приведение типов для конкретного случая и реализован ли в нем оператор сложения для нужных типов. Например, в Ruby «a» * 3 выдает «aaa». В C++ тоже можно сделать свой строковый тип и реализовать такое же поведение. И что теперь, C++ тоже динамически типизирован? Нет.
5) Устанавливаем “гостевую ОС”.
В VirtulBox активизируем образ “гостевой ОС”
производим установку “гостевой ОС”
Похоже, вы не понимаете фразу «Подключить образ диска дополнений гостевой ОС». Гостевая ОС — это ОС внутри виртуальной машины, в данном случае ReactOS. На этом этапе она, очевидно, уже установлена. А устанавливаете вы дополнения для гостевой ОС — драйверы и прочие штуки, улучшающие ее интеграцию с VirtualBox (например, динамическое изменение разрешения экрана гостевой ОС при изменении размера окна VirtualBox).
Могли бы мили в километры перевести.
А может, это фишинговый сайт. Домен-то другой.
В QtWidgets удобно выносить содержимое форм в ui-файлы, они тоже отлично структурированы и компактны. В конструкторах тогда остается намного меньше кода.

Хотя развитие QtWidgets замедлилось, о его выпиливании в обозримом будущем и речи быть не может. QML не сравнился с ним ни по функциональности, ни по легковесности. И вряд ли когда-нибудь сравнится.

Информация

В рейтинге
Не участвует
Откуда
Долгопрудный, Москва и Московская обл., Россия
Дата рождения
Зарегистрирован
Активность