"\n" - это символ не конца строки, а символ разделителя строк - и если это держать в уме, то все работает четко и корректно. Т.е. кол-во строк в файле = кол-во "\n" в файле + 1. Нет ни одного "\n" в файле - есть только одна строка, есть - минимум две строки.
А вот разработчики языков Python, C++ и Rust с вами не согласны. :)(:
Возьмём для примера два файла with_ending_newline.txt и without_ending_newline.txt. Первый содержит "a\nb\n", а второй — "a\nb". Если читать эти файлы по строкам используя readlines()/getline()/read_line(), то будет прочитано две строки во всех случаях:
// [https://stackoverflow.com/questions/45882329/read-large-files-line-by-line-in-rust <- google:‘rust read lines from file’]
use std::fs::File;
use std::io::{self, prelude::*, BufReader};
fn main() -> io::Result<()> {
let file = File::open("/uploads/with_ending_newline.txt")?;
let reader = BufReader::new(file);
let mut total = 0;
for line in reader.lines() {
println!("{}", line?);
total += 1;
}
println!("Total lines: {}", total);
Ok(())
}
// [https://stackoverflow.com/questions/63627687/why-does-rusts-read-line-function-use-a-mutable-reference-instead-of-a-return-v <- https://stackoverflow.com/search?q=rust+read_line]
use std::fs::File;
use std::io::{self, prelude::*, BufReader};
fn main() -> io::Result<()> {
let file = File::open("/uploads/with_ending_newline.txt")?;
let mut reader = BufReader::new(file);
let mut total = 0;
let mut line = String::new();
while reader.read_line(&mut line)? != 0 {
println!("{}", line);
total += 1;
line.clear();
}
println!("Total lines: {}", total);
Ok(())
}
Обратите внимание, вывод для файлов with_ending_newline.txt и without_ending_newline.txt немного отличается, но в обоих случаях Total lines: 2.
автор ... не понимает, что такое "\n" - и от этого вся проблема и борьба с ветрянными мельницами.
Автор пытается обратить внимание читателей на то, что функции feof()/eof() в C/C++ однозначно можно признать неудачными/[сбивающими с толку], т.к. во всех новых языках программирования ничего подобного этим функциям просто нет — в Python вообще никакого eof-а нет, а в Nim, Rust и Swift eof() работает как в старом добром Паскале (ну только называется немного по другому: endOfFile() в Nim, !has_data_left() в Rust, availableData.count == 0 в Swift).
На уточняющие вопросы студентов я всегда охотно отвечаю, но прямого вопроса «почему у меня читается лишняя пустая строка» я не получал, а заметил это сам в процессе отладки решения одного из студентов.
«Смысл этого чтения» излагается в тексте задания и в данной статье не приводится, так как приводить полный текст задания в данной статье я посчитал излишним. Суть в том, что на входе есть текстовый файл со списком слов на английском языке и их переводом.
Каждая строка файла содержит:
<слово> - <перевод>
Конкретно в данной задаче пустые строки можно просто игнорировать, или можно удалять последнюю строку из массива прочитанных строк (в этом случае программа станет работать некорректно после добавления во входной файл строки, которая не оканчивается на символ новой строки), что, собственно, и делали студенты, пока я не обратил на это внимание и не решился разобраться подробно.
Смотрите, в чём проблема. Допустим, есть такая программка на Python:
print('a')
print('b')
Она выводит в консоль две строки:
a
b
Теперь, если перенаправить вывод этой программы в файл (python prog.py > out.txt), то логично будет ожидать, что в файле будут всего две строки, а не три ['a', 'b' и ''].
Это значит, что строк столько же, сколько и этих символов + 1 вначале файла.
Если следовать такой логике, то получится, что в файле out.txt три строки (два символа \n + 1), а должно быть две.
"Поэтому я и сделал замечание, что данная запись в C++17 зачастую требуется для другого, и привёл соответствующий код." Для какого другого?
Ну фича эта довольно новая, и сейчас непросто найти хорошие примеры из реальных проектов на C++, где она бы использовалась. Но предполагаемые варианты использования можно посмотреть в proposal и в статьях.
пустую введенную человеком строку, то молча игнорировать ее будет как минимум невежливо.
Не соглашусь. Всё зависит от задачи. Вам разве никогда не встречалась фраза в скобках оставьте пустым, чтобы пропустить? Вот примеры приглашений для ввода из скрипта установки Arch Linux:
Напишите дополнительные пакеты для установки (разделите пробелами, оставьте пустым, чтобы пропустить):
Любые дополнительные пользователи для установки (оставьте пустым, если пользователей нет):
Введите IP-адрес вашего шлюза (маршрутизатора) или оставьте пустым, если его нет:
Введите ваши DNS-серверы (через пробел, пустой - нет):
Введите пароль шифрования диска (оставьте пустым для отсутствия шифрования):
Введите имя пользователя (оставьте пустым, чтобы пропустить):
А я за задержку не извиняюсь. Просто думаю долго. :)(:
В этом примере input возвращает или введенную строку или магическое значение пустая строка "", если ничего не ввели.
Постойте-постойте, мы наверное [думаем/]говорим о каком-то разном input. Когда в программе на Python вызывается функция input(), ожидается ввод строки от пользователя [обычно через консоль]. Пользователь вводит строку и нажимает Enter. Если был набран только один символ до нажатия Enter, то возвращаемая функцией input() строка будет состоять из одного символа. Если не было набрано ни одного [символа] (т.е. пользователь сразу нажал Enter) — то возвращаемая строка будет пустая. Т.е. пустая строка — это не какое-то магическое значение. Оно вообще никак особым образом не обрабатывается, а получается как бы само собой [ну, так вышло, что символов перед нажатием Enter набрано не было, либо они все были стёрты клавишей Backspace].
При этом теряется возможность различить не веденную строку и пустую введенную строку.
Тут, похоже, вы имеете в виду нечто другое: «не введённая строка» — это ошибка, возникшая во время вызова input()? Вообще, я считаю, что ошибки во время конкретного вызова input() обрабатывать явно программисту не требуется в >99% случаев. Когда в коде написано password = input('Enter password:'), программист ожидает, что после выполнения этой строки кода можно спокойно обращаться к password как к строке и это вполне нормально. [Возможно, программист захочет проверить, что эта строка не пустая или ещё что-то, но он уж точно не ожидает, что password может оказаться установленным в None.]
В идиоматическом Аргентуме функция input() будет возвращать ?String
А как в «идиоматическом Аргентуме» обработать реальные ошибки, которые могут возникнуть во время вызова input()? В Python это решается исключениями [упоминания исключений в описании Аргентума я не нашёл]. Конкретно при выполнении input() могут возникнуть следующие исключения:
KeyboardInterrupt — возникает при нажатии Ctrl+C;
EOFError — возникает, если на момент вызова input() уже достигнут конец файла (в случае, когда поток стандартного ввода был перенаправлен, т.е. когда ввод читается из файла, например, а не с клавиатуры);
UnicodeDecodeError — возникает, когда перенаправленный стандартный ввод содержит данные, которые не удаётся преобразовать в Unicode строку (т.е. опять же когда ввод читается из файла, т.к. при вводе с клавиатуры такого исключения возникнуть не может).
Ещё раз повторю своё утверждение "я считаю, что ошибки во время конкретного вызова input() обрабатывать явно программисту не требуется в >99% случаев". Потому-то я и привёл в своём примере именно функцию input(), никак не ожидая с вашей стороны дикую мысль "input() будет возвращать ?String". Но для большей ясности моего вопроса "Как такое сделать в Аргентум [без вспомогательной функции-предиката]?" сделаю два уточнения:
подставьте на место input() любую другую функцию, возвращающую только строку, а на место != "" — любую другую const-операцию со строкой;
на месте use(line) может быть не просто одиночный вызов функции, а блок кода, причём довольно большой, поэтому использование _ тут нежелательно, и я имел в виду именно создание/объявление новой полноценной переменной (line в ‘моём примере’/‘данном случае’).
That's why the new C++17 if got its new convenient syntax:
if (auto v = expression(); predicate(v)) use (v);
... The AG binary "?"-operator with optional operand we can achieve the same functionality without extra syntax:
predicate(extression()) ? use(_);
Т.е. вы утверждаете, что данный функционал C++17 поддерживается в Аргентуме, хотя, похоже, имеете в виду лишь частный случай if (...; predicate(v)). Поэтому я и сделал замечание, что данная запись в C++17 зачастую требуется для другого, и привёл соответствующий код.
Если ваш язык это не поддерживает — ничего страшного (это всего лишь щепотка синтаксического сахара, и в том же C++ это появилось только в C++17 — раньше как-то программисты C++ жили без этого и ничего). Просто так и скажите об этом прямо.
Моё замечание [о наличии ошибки] относилось только к первому фрагменту Python-кода в вашем комментарии. Признаюсь честно, второй фрагмент [с suppress] я даже не заметил. :)(: Или просто не воспринял всерьёз. И вот почему. Весь смысл задачи ‘чтобы поиск key в dic всегда осуществлялся только один раз’ заключается в повышении производительности этого кода. Чтобы не делать [второй] лишний поиск key в dic. Ваше же решение с suppress в данном контексте просто не имеет смысла [и всерьёз его воспринимать нельзя]. Порождение исключения при каждом обращении к отсутствующему ключу в словаре — это очень-очень дорого. [Лишний поиск key в dic обойдётся гораздо дешевле.] Вот простенький бенчмарк, который показывает в 5 раз меньшую производительность кода с suppress [по сравнению с кодом с лишним поиском key в dic]. Но в любом компилируемом языке программирования разница будет гораздо больше.
Удивительно, что до сих пор никто не увидел ошибку в вашем комментарии. Для очевидности [в чём ваша ошибка], обернём код из статьи в функцию и добавим тестовый вывод для проверки корректности изменений кода:
Экспериментирование поощряется наличием playground-ов, где все самое важное уже импортировано.
Не встречал ни одного playground-а, который бы импортировал хоть что-то неявно [т.е. сверх того, что явно импортируется в коде на странице playground-а]. По вашей же ссылке на play.rust-lang.org не заметно, что "всё самое важное уже импортировано". Один из наиболее продвинутых playground-ов — Repl.it — умеет автоматически устанавливать пакеты при попытке их импортирования в коде (т.е. import markdown приведёт к автоустановке этого пакета). Считаю, что аналогичное поведение компилятора, установленного локально, вполне допустимо.
Для полноценного экспериментирования как правило необходима возможность чтения файлов [текстовых, а иногда и двоичных], что поддерживается далеко не всеми playground-ами (многие playground-ы не поддерживают даже консольный ввод). И даже если и поддерживается, часто нужна достаточно высокая производительность (к примеру, требуется найти какие-то закономерности в большом наборе текстов).
Вот как раз необязательность и является претензией. Начиная с того, что таким образом вы усложняете жизнь тем же реестрам...
Необязательность тоже можно ограничить. Когда программа/модуль/библиотека выкладывается в какой-то реестр/‘публичный репозиторий’, к ней предъявляются определённые требования (наличие лицензии, номер версии, указание зависимостей и прочее), но на этапе экспериментирования можно минимизировать количество этих формальностей [и только небольшое количество кода преодолевает этап экспериментирования и используется кем-то кроме его разработчиков].
Сами-то небось хотите, чтобы сразу было видно, кто вашу библиотеку использует, и что у других в зависимостях.
А разве сейчас видно, кто использует какой-то пакет npm или модуль Python за пределами этого же реестра [npmjs.com или pypi.org в данном случае]? Я имею в виду, в каких проектах на GitHub/GitLab/Bitbucket/SourceForge он используется.
В любом случае, пользователей библиотек гораздо больше, чем разработчиков библиотек. И почему бы не упростить [хоть немного] жизнь пользователям?
Но все вышесказанной просто меркнет по сравнению с одной банальностью -- у вас все равно в любом проекте зависимости от конкретных версий библиотек.
Нет, не в любом. У меня довольно много скриптов [на Python], состоящих всего из одного файла. Причём порой даже над именем файла я не особо задумывался (а у некоторых вместо названия просто число — порядковый номер этого скрипта). И есть много публичных библиотек, которые уже давно "устаканились" и вообще практически не обновляются — при их использовании нет смысла указывать номер версии.
Автоматически скачивать что-то при компиляции просто при упоминании -- это же готовый бекдор.
Ну, можно ведь как-то помечать модули в реестре и автоматически скачивать и устанавливать при компиляции только модули с пометкой trusted.
То, что библиотеки/пакеты необходимо устанавливать отдельными командами никак не защищает от наличия вредоносного кода внутри этих библиотек, т.к. проверять исходный код каждой подключаемой библиотеки рядовому программисту просто нереально.
Если вы имеете в виду то, что при попытке обращения в коде к модулю с именем скажем backdoors_collection компилятор скачает и установит этот модуль без ведома программиста (а иначе увидев модуль с таким странным именем программист хорошо подумает, прежде чем устанавливать его), так это решается вот этой самой пометкой trusted, ибо никакой модуль с таким подозрительным именем [даже если в нём и не будет вредоносного кода] такую пометку не получит.
Т.е. думать ‘всё равно ’|надо|‘ в любом случае’. Просто есть два варианта:
Думать каждому программисту, безопасно ли подключать/устанавливать данный модуль/библиотеку.
Или думать только модератору реестра [или совету модераторов] ставить пометку trusted добавленному в реестр модулю или не ставить [очевидно, что по умолчанию trusted стоять не должно].
И тут, я считаю, второй вариант будет даже безопаснее.
А вообще суть идеи с автоустановкой модулей/пакетов в том, чтобы поощрять экспериментирование и упрощать обмен кодом: увидел фрагмент кода на Stack Overflow — вставил в свою программу и запустил (при этом не нужно ни лезть в начало исходного файла и дописывать в import имена модулей, которые используются в этом фрагменте кода, ни устанавливать эти модули).
Есть дефолтный реестр, и можно явно указывать, из какого брать.
Так я ж не против. Указывать это всё можно (как я и написал в статье: "Если требуется не последняя версия пакета/модуля, это можно указать в файле конфигурации/сборки проекта." [внутри спойлера "Немного технических подробностей"]). Речь о том, чтобы указывать это [какие модули необходимы программе] было не обязательно.
Ваше первое утверждение было "Никто не знает", сейчас скатились на "Никто не умеет". Что дальше?
Как я уже писал в данной статье: """Под знанием я подразумеваю не просто какую-то гору информации на эту тему, а возможность на практике повторить процесс изготовления"""
А "Шестеренки 100-летней давности" это 1924 год? Промышленное производство? вы серьезно?
Шестеренки могли вообще не рисовать, передавали устно технологии или оставляли образец рабочий и все.
Рабочий образец чего? Шестерёнки или станка, посредством которого она была изготовлена? В любом случае, я повторю своё утверждение о том, что сейчас нет[/не осталось] людей, которые могли бы повторить такой процесс на практике [процесс изготовления шестерёнки для наручных часов 100-летней давности].
Если копать глубже, можете обрисовать как вы видите процесс изготовления одной шестерёнки для наручных механических часов? Причём, не современных часов, а тех, что производились ещё около 100 лет назад. По какой причине этот процесс нигде подробно не описан?
Вояджер стал посылать на Землю хаотические данные просто потому что долбанулся в этот экран? А тогда почему второй не долбанулся?
Вы указали на очень интересный факт. Насколько я понимаю, речь идёт об этой новости от 13.12.2023. На данный момент Вояджер-1 находится на расстоянии 162.2 а.е. от Солнца, а Вояджер-2 — 135.4 а.е. Посмотрим, что будет, когда Вояджер-2 долетит также далеко от Солнца, как Вояджер-1.
Однако, обращаю внимание на два момента:
Вы почему-то приняли за размер Солнечной системы величину радиуса гелиосферы (и именно гелиосферу покинул Вояджер), но за размер Солнечной системы можно принять расстояние до внешних границ облака Оорта [цитата оттуда: «Внешняя часть облака Оорта является приблизительной границей Солнечной системы»], которое составляет от 50000 до 100000 а.е.
В статье неспроста использована фраза "вокруг Солнечной системы", а не "на границе Солнечной системы". Другими словами: упомянутый в статье "экран" располагается за пределами Солнечной системы, т.е. он может располагаться сколь угодно далеко от Солнца.
Откуда эта паника? А представьте, что ИИ научится понимать и анализировать исходный код открытого (и машинный код закрытого) всего существующего ПО на планете и генерировать новый код. И незаметно для человека нагенерирует и сохранит на каком-то сервере бесчисленное количество эксплойтов. А затем создаст маленький скрипт-загрузчик, который обращается к этой базе эксплойтов. Достаточно хотя бы одному пользователю хотя бы один раз запустить этот скрипт-загрузчик — и вуяля! Используя найденные уязвимости в существующем ПО щупальца ИИ в считанные дни (а то и часы) распространятся по всей планете: в каждый компьютер, в каждый смартфон, в каждое IoT-устройство, до которого получится дотянуться. Причём не просто распространятся, а так прилипнут, что никакими антималварями их уже не вытащить (ибо все дистрибутивы на всех "официальных" сайтах будут уже заражены [сколько там гигабайт занимает дистрибутив Windows 11? если к нему добавится мегабайт 100 "подарочка от ИИ" никто даже и не заметит], заражены будут все компиляторы и генерировать будут уже заражённый код). И теперь уже физически будет не "ИИ - это большой дата-центр", а "все компьютеризированные устройства планеты — это большой дата-центр под управлением/контролем ИИ". Как вам такой вариант развития событий?
А вот разработчики языков Python, C++ и Rust с вами не согласны. :)(:
Возьмём для примера два файла
with_ending_newline.txt
иwithout_ending_newline.txt
.Первый содержит
"a\nb\n"
, а второй —"a\nb"
.Если читать эти файлы по строкам используя readlines()/getline()/read_line(), то будет прочитано две строки во всех случаях:
Python
(Ссылка на playground)
C++
(Ссылка на playground)
Rust с использованием lines()
(Ссылка на playground)
Rust с использованием read_line()
(Ссылка на playground)
Обратите внимание, вывод для файлов
with_ending_newline.txt
иwithout_ending_newline.txt
немного отличается, но в обоих случаяхTotal lines: 2
.Автор пытается обратить внимание читателей на то, что функции
feof()
/eof()
в C/C++ однозначно можно признать неудачными/[сбивающими с толку], т.к. во всех новых языках программирования ничего подобного этим функциям просто нет — в Python вообще никакого eof-а нет, а в Nim, Rust и Swifteof()
работает как в старом добром Паскале (ну только называется немного по другому: endOfFile() в Nim, !has_data_left() в Rust, availableData.count == 0 в Swift).Зря вы так.
На уточняющие вопросы студентов я всегда охотно отвечаю, но прямого вопроса «почему у меня читается лишняя пустая строка» я не получал, а заметил это сам в процессе отладки решения одного из студентов.
«Смысл этого чтения» излагается в тексте задания и в данной статье не приводится, так как приводить полный текст задания в данной статье я посчитал излишним. Суть в том, что на входе есть текстовый файл со списком слов на английском языке и их переводом.
Каждая строка файла содержит:
<слово> - <перевод>
Конкретно в данной задаче пустые строки можно просто игнорировать, или можно удалять последнюю строку из массива прочитанных строк (в этом случае программа станет работать некорректно после добавления во входной файл строки, которая не оканчивается на символ новой строки), что, собственно, и делали студенты, пока я не обратил на это внимание и не решился разобраться подробно.
А как вы предлагаете отличать пустую строку в самом конце файла от пустых строк в середине?
Хорошо, если все пустые строки можно просто игнорировать. Но в некоторых задачах промежуточные пустые строки имеют значение.
Смотрите, в чём проблема. Допустим, есть такая программка на Python:
Она выводит в консоль две строки:
Теперь, если перенаправить вывод этой программы в файл (
python prog.py > out.txt
), то логично будет ожидать, что в файле будут всего две строки, а не три ['a'
,'b'
и''
].Если следовать такой логике, то получится, что в файле
out.txt
три строки (два символа\n
+ 1), а должно быть две.И чем вам инкремент не угодил...
Вот у меня есть такой метод в классе:
Если отказаться от инкремента, тогда придётся этот метод переписать так:
Неужели, по вашему, стало понятнее?
Ну фича эта довольно новая, и сейчас непросто найти хорошие примеры из реальных проектов на C++, где она бы использовалась. Но предполагаемые варианты использования можно посмотреть в proposal и в статьях.
Не соглашусь. Всё зависит от задачи. Вам разве никогда не встречалась фраза в скобках
оставьте пустым, чтобы пропустить
?Вот примеры приглашений для ввода из скрипта установки Arch Linux:
А я за задержку не извиняюсь. Просто думаю долго. :)(:
Постойте-постойте, мы наверное [думаем/]говорим о каком-то разном input.
Когда в программе на Python вызывается функция
input()
, ожидается ввод строки от пользователя [обычно через консоль]. Пользователь вводит строку и нажимает Enter.Если был набран только один символ до нажатия Enter, то возвращаемая функцией
input()
строка будет состоять из одного символа. Если не было набрано ни одного [символа] (т.е. пользователь сразу нажал Enter) — то возвращаемая строка будет пустая. Т.е. пустая строка — это не какое-то магическое значение. Оно вообще никак особым образом не обрабатывается, а получается как бы само собой [ну, так вышло, что символов перед нажатием Enter набрано не было, либо они все были стёрты клавишей Backspace].Тут, похоже, вы имеете в виду нечто другое: «не введённая строка» — это ошибка, возникшая во время вызова
input()
?Вообще, я считаю, что ошибки во время конкретного вызова
input()
обрабатывать явно программисту не требуется в >99% случаев. Когда в коде написаноpassword = input('Enter password:')
, программист ожидает, что после выполнения этой строки кода можно спокойно обращаться кpassword
как к строке и это вполне нормально. [Возможно, программист захочет проверить, что эта строка не пустая или ещё что-то, но он уж точно не ожидает, чтоpassword
может оказаться установленным вNone
.]А как в «идиоматическом Аргентуме» обработать реальные ошибки, которые могут возникнуть во время вызова
input()
?В Python это решается исключениями [упоминания исключений в описании Аргентума я не нашёл]. Конкретно при выполнении
input()
могут возникнуть следующие исключения:KeyboardInterrupt
— возникает при нажатии Ctrl+C;EOFError
— возникает, если на момент вызоваinput()
уже достигнут конец файла (в случае, когда поток стандартного ввода был перенаправлен, т.е. когда ввод читается из файла, например, а не с клавиатуры);UnicodeDecodeError
— возникает, когда перенаправленный стандартный ввод содержит данные, которые не удаётся преобразовать в Unicode строку (т.е. опять же когда ввод читается из файла, т.к. при вводе с клавиатуры такого исключения возникнуть не может).Ещё раз повторю своё утверждение "я считаю, что ошибки во время конкретного вызова
input()
обрабатывать явно программисту не требуется в >99% случаев". Потому-то я и привёл в своём примере именно функциюinput()
, никак не ожидая с вашей стороны дикую мысль "input() будет возвращать ?String". Но для большей ясности моего вопроса "Как такое сделать в Аргентум [без вспомогательной функции-предиката]?" сделаю два уточнения:подставьте на место
input()
любую другую функцию, возвращающую только строку, а на место!= ""
— любую другую const-операцию со строкой;на месте
use(line)
может быть не просто одиночный вызов функции, а блок кода, причём довольно большой, поэтому использование_
тут нежелательно, и я имел в виду именно создание/объявление новой полноценной переменной (line
в ‘моём примере’/‘данном случае’).Вообще, мой вопрос был навеян вашей фразой в The Argentum Book:
Т.е. вы утверждаете, что данный функционал C++17 поддерживается в Аргентуме, хотя, похоже, имеете в виду лишь частный случай
if (...; predicate(v))
. Поэтому я и сделал замечание, что данная запись в C++17 зачастую требуется для другого, и привёл соответствующий код.Если ваш язык это не поддерживает — ничего страшного (это всего лишь щепотка синтаксического сахара, и в том же C++ это появилось только в C++17 — раньше как-то программисты C++ жили без этого и ничего). Просто так и скажите об этом прямо.
Моё замечание [о наличии ошибки] относилось только к первому фрагменту Python-кода в вашем комментарии.
Признаюсь честно, второй фрагмент [с
suppress
] я даже не заметил. :)(: Или просто не воспринял всерьёз.И вот почему.
Весь смысл задачи ‘чтобы поиск
key
вdic
всегда осуществлялся только один раз’ заключается в повышении производительности этого кода. Чтобы не делать [второй] лишний поискkey
вdic
. Ваше же решение сsuppress
в данном контексте просто не имеет смысла [и всерьёз его воспринимать нельзя]. Порождение исключения при каждом обращении к отсутствующему ключу в словаре — это очень-очень дорого. [Лишний поискkey
вdic
обойдётся гораздо дешевле.]Вот простенький бенчмарк, который показывает в 5 раз меньшую производительность кода с
suppress
[по сравнению с кодом с лишним поискомkey
вdic
]. Но в любом компилируемом языке программирования разница будет гораздо больше.Удивительно, что до сих пор никто не увидел ошибку в вашем комментарии.
Для очевидности [в чём ваша ошибка], обернём код из статьи в функцию и добавим тестовый вывод для проверки корректности изменений кода:
А теперь попробуйте переписать этот Python-код таким образом, чтобы поиск
key
вdic
внутри функцииf
всегда осуществлялся только один раз.Не встречал ни одного playground-а, который бы импортировал хоть что-то неявно [т.е. сверх того, что явно импортируется в коде на странице playground-а]. По вашей же ссылке на play.rust-lang.org не заметно, что "всё самое важное уже импортировано". Один из наиболее продвинутых playground-ов — Repl.it — умеет автоматически устанавливать пакеты при попытке их импортирования в коде (т.е.
import markdown
приведёт к автоустановке этого пакета). Считаю, что аналогичное поведение компилятора, установленного локально, вполне допустимо.Для полноценного экспериментирования как правило необходима возможность чтения файлов [текстовых, а иногда и двоичных], что поддерживается далеко не всеми playground-ами (многие playground-ы не поддерживают даже консольный ввод). И даже если и поддерживается, часто нужна достаточно высокая производительность (к примеру, требуется найти какие-то закономерности в большом наборе текстов).
Необязательность тоже можно ограничить. Когда программа/модуль/библиотека выкладывается в какой-то реестр/‘публичный репозиторий’, к ней предъявляются определённые требования (наличие лицензии, номер версии, указание зависимостей и прочее), но на этапе экспериментирования можно минимизировать количество этих формальностей [и только небольшое количество кода преодолевает этап экспериментирования и используется кем-то кроме его разработчиков].
А разве сейчас видно, кто использует какой-то пакет npm или модуль Python за пределами этого же реестра [npmjs.com или pypi.org в данном случае]? Я имею в виду, в каких проектах на GitHub/GitLab/Bitbucket/SourceForge он используется.
В любом случае, пользователей библиотек гораздо больше, чем разработчиков библиотек. И почему бы не упростить [хоть немного] жизнь пользователям?
Нет, не в любом. У меня довольно много скриптов [на Python], состоящих всего из одного файла. Причём порой даже над именем файла я не особо задумывался (а у некоторых вместо названия просто число — порядковый номер этого скрипта).
И есть много публичных библиотек, которые уже давно "устаканились" и вообще практически не обновляются — при их использовании нет смысла указывать номер версии.
Ну, можно ведь как-то помечать модули в реестре и автоматически скачивать и устанавливать при компиляции только модули с пометкой trusted.
То, что библиотеки/пакеты необходимо устанавливать отдельными командами никак не защищает от наличия вредоносного кода внутри этих библиотек, т.к. проверять исходный код каждой подключаемой библиотеки рядовому программисту просто нереально.
Если вы имеете в виду то, что при попытке обращения в коде к модулю с именем скажем
backdoors_collection
компилятор скачает и установит этот модуль без ведома программиста (а иначе увидев модуль с таким странным именем программист хорошо подумает, прежде чем устанавливать его), так это решается вот этой самой пометкой trusted, ибо никакой модуль с таким подозрительным именем [даже если в нём и не будет вредоносного кода] такую пометку не получит.Т.е. думать ‘всё равно ’|надо|‘ в любом случае’. Просто есть два варианта:
Думать каждому программисту, безопасно ли подключать/устанавливать данный модуль/библиотеку.
Или думать только модератору реестра [или совету модераторов] ставить пометку trusted добавленному в реестр модулю или не ставить [очевидно, что по умолчанию trusted стоять не должно].
И тут, я считаю, второй вариант будет даже безопаснее.
А вообще суть идеи с автоустановкой модулей/пакетов в том, чтобы поощрять экспериментирование и упрощать обмен кодом: увидел фрагмент кода на Stack Overflow — вставил в свою программу и запустил (при этом не нужно ни лезть в начало исходного файла и дописывать в import имена модулей, которые используются в этом фрагменте кода, ни устанавливать эти модули).
Так я ж не против. Указывать это всё можно (как я и написал в статье: "Если требуется не последняя версия пакета/модуля, это можно указать в файле конфигурации/сборки проекта." [внутри спойлера "Немного технических подробностей"]).
Речь о том, чтобы указывать это [какие модули необходимы программе] было не обязательно.
Как же она его изменяет, если это
const std::set<int>
? :)(:Без
const
— да, имеет смысл (хоть и редко).Резюмируя, в C++03 существует 4 способа передачи аргумента типа
std::set<int>
в функцию:И вот третий из них — смысла не имеет.
Да, вы правы. Поправил.
Как я уже писал в данной статье:
"""Под знанием я подразумеваю не просто какую-то гору информации на эту тему, а возможность на практике повторить процесс изготовления"""
Первый Московский часовой завод был основан в 1930 году, но работал на оборудовании американской компании Dueber-Hampden Watch Company, основанной в 19 веке.
Рабочий образец чего? Шестерёнки или станка, посредством которого она была изготовлена?
В любом случае, я повторю своё утверждение о том, что сейчас нет[/не осталось] людей, которые могли бы повторить такой процесс на практике [процесс изготовления шестерёнки для наручных часов 100-летней давности].
Речь про наручные часы. Вас не смущает, что человек не может даже начертить шестерёнку таких часов в натуральную величину?
Если копать глубже, можете обрисовать как вы видите процесс изготовления одной шестерёнки для наручных механических часов? Причём, не современных часов, а тех, что производились ещё около 100 лет назад.
По какой причине этот процесс нигде подробно не описан?
В 11l это легко понять: если стоит квалификатор
&
, значит функция может модифицировать переменную. Если не стоит квалификатора — значит не может.Для этого в 11l присутствует два вида деструкторов.
Деструктор
f
(который закрывает файл) будет вызван сразу послеf.write('int main() {}')
. Или что вы имеете в виду под финализацией?Вы указали на очень интересный факт. Насколько я понимаю, речь идёт об этой новости от 13.12.2023.
На данный момент Вояджер-1 находится на расстоянии 162.2 а.е. от Солнца, а Вояджер-2 — 135.4 а.е. Посмотрим, что будет, когда Вояджер-2 долетит также далеко от Солнца, как Вояджер-1.
Однако, обращаю внимание на два момента:
Вы почему-то приняли за размер Солнечной системы величину радиуса гелиосферы (и именно гелиосферу покинул Вояджер), но за размер Солнечной системы можно принять расстояние до внешних границ облака Оорта [цитата оттуда: «Внешняя часть облака Оорта является приблизительной границей Солнечной системы»], которое составляет от 50000 до 100000 а.е.
В статье неспроста использована фраза "вокруг Солнечной системы", а не "на границе Солнечной системы". Другими словами: упомянутый в статье "экран" располагается за пределами Солнечной системы, т.е. он может располагаться сколь угодно далеко от Солнца.
Откуда эта паника? А представьте, что ИИ научится понимать и анализировать исходный код открытого (и машинный код закрытого) всего существующего ПО на планете и генерировать новый код. И незаметно для человека нагенерирует и сохранит на каком-то сервере бесчисленное количество эксплойтов. А затем создаст маленький скрипт-загрузчик, который обращается к этой базе эксплойтов. Достаточно хотя бы одному пользователю хотя бы один раз запустить этот скрипт-загрузчик — и вуяля! Используя найденные уязвимости в существующем ПО щупальца ИИ в считанные дни (а то и часы) распространятся по всей планете: в каждый компьютер, в каждый смартфон, в каждое IoT-устройство, до которого получится дотянуться. Причём не просто распространятся, а так прилипнут, что никакими антималварями их уже не вытащить (ибо все дистрибутивы на всех "официальных" сайтах будут уже заражены [сколько там гигабайт занимает дистрибутив Windows 11? если к нему добавится мегабайт 100 "подарочка от ИИ" никто даже и не заметит], заражены будут все компиляторы и генерировать будут уже заражённый код). И теперь уже физически будет не "ИИ - это большой дата-центр", а "все компьютеризированные устройства планеты — это большой дата-центр под управлением/контролем ИИ". Как вам такой вариант развития событий?