Учебник по языку программирования D. Часть 4
Четвертая часть перевода D Programming Language Tutorial от Ali Çehreli.Другие части: Конкретные понятия, которые представлены в программе, называются переменными. Значение вроде температура воздуха или более сложный объект, как двигатель машины, могут быть переменными в программе.Каждая переменная имеет определенный тип и определенное значение. Большинство переменных также имеют имена, но некоторые являются анонимными.
В качестве примера переменной мы можем рассматривать концепцию числа учеников в школе. Так как число студентов является целым числом, int — подходящий тип, и studentCount будет достаточно описывающим именем.
Согласно синтаксическим правилам D переменная начинается с ее типа с последующим именем. Введение переменной в программу называется определением. Как только переменная определена, ее имя начинает представлять ее значение.
import std.stdio; void main (){ // Определение переменной; это определение // указывает, что типом studentCount является int: int studentCount; // Название переменной становится ее значением: writeln («Присутствует », studentCount, » учеников.»);}
Вывод этой программы:
Присутствует 0 учеников Как видно из этой строки, значение studentCount равно 0. Согласно таблице фундаментальных типов из прошлой главы: начальное значение int равно 0.
Заметьте, что строка studentCount не появляется в выводе. Другими словами, программа не выводит «Присутствует studentCount учеников».
Значения переменных изменяются с помощью оператора =. Оператор = присваивает новые значения переменным, и по этой причине и называется оператором присвоения:
import std.stdio; void main (){ int studentCount; writeln («Присутствует », studentCount, » учеников.»); // Присваивание значения 200 переменной studentCount: studentCount = 200; writeln («Теперь присутствует », studentCount, » учеников.»);}
Присутствует 0 учеников. Теперь присутствует 200 учеников. Когда значение переменной известно в момент определения, значение переменной может быть присвоено одновременно с ее определением. Это важный принцип; это делает невозможным использование переменной до момента присвоения предназначенного ей значения:
import std.stdio; void main (){ // Одноврменное определение и присвоение значения: int studentCount = 100; writeln («Присутствует », studentCount, » учеников.»);}
Присутствует 100 учеников. Упражнения Определите две переменные для вывода «Я обменял 20 евро по курсу 2.11». Для значения с плавающей точкой используйте double… решение import std.stdio; void main (){int amount = 20; double rate = 2.11;
writeln («Я обменял », amount,» евро по курсу », rate);}-->
import std.stdio; void main (){ int amount = 20; double rate = 2.11; writeln («Я обменял », amount, » евро по курсу », rate);}
До этого момента весь напечатанный вывод наших программ появлялся в окне консоли. Хотя это на самом деле часто используется многими программами, на самом деле символы выводятся в стандартные потоки вывода.Стандартный вывод основан на символах; все, что печатается, сначала конвертируется в символьное представление и потом последовательно отправляется на вывод как символы. Например, целочисленное значение 100, которое мы выводили в прошлой главе не посылается на вывод как значение 100, а как три символа 1, 0 и 0.
Аналогично то, что мы обычно воспринимаем как клавиатура, на самом деле является стандартным потоком ввода программы, и он также основан на символах. Информация всегда поступает как символы для конвертацию в данные. Для примера целочисленное значение 42 на самом деле приходит через стандартный ввод как символы 4 и 2.
Эти преобразования производятся автоматически.
Это понятие последовательных символов называется символьным потоком. Так как стандартный поток ввода и стандартный поток вывода подходят под это описание, они являются символьными потоками.
Названия стандартных потоков ввода и вывода в D — stdin и stdout соответственно.
Операции над этими потоками обычно требуют имя потока, точку и название операции; например stream.operation (). Так как stdin и stdout используются очень часто, по соглашению, стандартные операции над ними могут быть вызываны без необходимости указывания имени и точки, например operation ().
writeln, которую мы использовали в предыдущих главах на самом деле является сокращением от stdout.writeln. Также write — сокращение от stdout.write. Соответственно программа «привет мир» может быть написана так:
import std.stdio; void main (){ stdout.writeln («Hello world!»);}
Упражнения Убедитесь, что stdout.write работает также, как write… решение import std.stdio; void main (){ stdout.writeln (1, »,», 2);}
Любые данные, которые были прочитаны программой, должны быть сперва сохранены в переменную. Например, программа, которая читает количество студентов из стандартного потока ввода, должна сохранить эту информацию в переменную. Типом этой конкретной переменной может быть int.Как мы убедились в предыдущей главе, нет необходимости указывать stdout, когда выводим информацию, так как он предполагается. Далее, то, что выводится, указывается как аргумент. Поэтому write (studentCount) достаточно, чтобы вывести значение studentCount. Подведем итог:
поток: stdout операция: write данные: значение переменной studentCount цель: обычно, окно терминала Обратная операции write — readf; она читает из стандартного потока ввода. Буква «f» в имени взята от «formatted», так как то, что читает эта функция, должно быть всегда представлено в определенном формате.
Также в прошлой главе мы узнали, что стандартный поток ввода называется stdin.
В случае чтения один кусочек головоломки все еще отсутствует: куда сохранить данные. Подведем итоги:
поток: stdin операция: readf данные: некоторая информация цель: ? Расположение места, куда необходимо сохранить данные, указывается с помощью адреса переменной. Адресом переменной является точное положение в памяти компьютера, где хранится ее значение.
В D символ '&', напечатанный перед именем, является указанием адреса того, что представляет эта переменная. Например, адресом studentCount является &studentCount. Здесь, &studentCount может быть прочитано как «адрес studentCount», и это недостающий кусок, который заменяет знак вопроса выше:
поток: stdin операция: readf данные: некоторая информация цель: расположение переменной studentCount Набор символа & перед именем означает взятие адреса того, что представляет это имя. Это понятие является основой ссылок и указателей, которые мы увидим в следующих главах.
Я отложу объяснение одной особенности использования readf; сейчас, примем правило о том, что первым аргументом readf должна быть строка »%s»:
readf (»%s», &studentCount); Заметка: Как я объясняю ниже, в большинстве случаев в строке также должен присутствовать пробел:» %s».
»%s» указывает, что данные должны быть автоматически преобразованы таким способом, который подходит под тип переменной. Например, когда символы '4' и '2' читаются в переменную типа int, они должны быть преобразованы в целочисленное значение 42.
Программа ниже просит пользователя ввести число учеников. Необходимо нажать клавишу Enter после окончания ввода:
import std.stdio; void main (){ write («Сколько присутствует учеников? »); /* * Объявление переменной, которая будет использована для * хранения информации, которая читается из потока ввода */ int studentCount; // Запись входных данных в эту переменную readf (»%s», &studentCount); writeln («Понял: Присутствует », studentCount, » учеников.»);}
Пропуск пробельных символов Даже клавиша Enter, которую мы нажимаем после ввода данных, сохраняется как специальный код и помещается в поток stdin. Это помогает программам обнаруживать, была ли информация введена в одной или нескольких строчках.Хотя это иногда полезно, такие специфические коды в большинстве случаев не важны для программы и должны быть удалены из ввода. Иначе они блокируют ввод и не дают читать другие данные.
Для демонстрации проблемы, давайте читать также число преподавателей из потока ввода:
import std.stdio; void main (){ write («Сколько присутствует учеников? »); int studentCount; readf (»%s», &studentCount); write («Сколько присутствует преподавателей? »); int teacherCount; readf (»%s», &teacherCount); writeln («Понял: Присутствует », studentCount, » учеников», » и», teacherCount, » преподавателей.»);}
К сожалению, теперь программа застряла при чтении второго int:
Сколько присутствует учеников? 100 Сколько присутствует преподавателей? 20 <- Программа зависает здесь Хотя пользователь ввел число преподавателей равным 20, специальные коды, которые представляют клавишу Enter при чтении предыдущего значения 100, все еще находятся в потоке ввода и блокируют его. Символы, которые хранятся в потоке ввода аналогичны следующим:
100[EnterCode]20[EnterCode] Первый символ [EnterCode] блокирует ввод.
Решением этой проблемы является добавление пробела перед %s для обозначения того, что код клавиши Enter, который может быть встречен перед чтением числа преподавателей, не важен:» %s». Пробелы в строке форматирования используются для чтения и игнорирования нуля или более невидимых символов, которые могут предшествовать вводу. Такие символы включают в себя: сам символ пробела, коды, которые представляют клавишу Enter, символ клавиши Tab и другие, называемые пробельными символами.
В общем случае можно использовать » %s» для любых данных, которые читаются из потока ввода. Программа выше работает как ожидается со следующими изменениями:
// … readf (» %s», &studentCount);// … readf (» %s», &teacherCount);// …
Вывод:
Сколько присутствует учеников? 100 Сколько присутствует преподавателей? 20 Понял: Присутствует 100 учеников и 20 преподавателей. Дополнительная информация Упражнения Введите не числовые символы, когда программа ожидает целочисленное значение и пронаблюдайте, как программа работает некорректно… решение Когда символы не могут быть преобразованы в желаемый тип, stdin переводится в состояние непригодное к использованию. Например, ввод «abc», когда ожидается int, сделает stdin непригодным к использованию.