Пятая часть перевода D Programming Language Tutorial от Ali Çehreli. В этой части переведена глава Logical Expressions. Материал главы рассчитан на новичков.
Фактическая работа, которую выполняет программа заключается в выражениях. Любая часть программы, которая создает значение или побочный эффект, называется выражением. Оно определяется широким понятием, потому что даже константное значение, скажем 42, и строковое, например «hello», это выражения, поскольку они создают эти соответствующие константы 42 и «hello».
Важно: Не путайте создание значения с декларацией переменной. Значениям не нужно привязываться к переменным.
Вызовы функции, например writeln — это выражения, кстати, потому что у них есть побочные эффекты. В случае с writeln, этот эффект накладывается на стандартный поток вывода печатанием символов на нем. Другим примером из программ, что мы написали ранее, может быть операция присвоения, которая изменяет переменную, которая стоит слева.
Из-за создания значений, выражения могут принимать участие в других выражениях. Это позволяет нам формировать более сложные выражения из более простых. Например, предположим, что есть функция названная currentTemperature, которая возвращает значение текущей температуры воздуха, это значение, что она производит, может быть непосредственно использоваться в выражении writeln:
Эта строка содержит следующее:
В этой главе мы обсудим конкретные типы выражений, которые используются в условных высказываниях.
Прежде, чем идти дальше я бы хотел повторить оператор присваивания еще раз, сейчас подчеркивая эти два выражения, что находятся на слева и справа от него. Оператор присваивания (=) присваивает значение указанного выражения справа выражению слева (например переменной).
Логические выражения — выражения, которые используются в Булевой алгебре. Логические выражения то, что делают компьютерные программы, принимая решения, вроде «если ответ Да, я сохраню файл».
Логические выражения могут иметь одно из двух значений: false, обозначающее ложь, и true, обозначающее истину.
Я буду использовать writeln выражения в следующих примерах. Если строка напечатала true в конце, это будет обозначать, что то, что напечатано в этой строке — это правда. Аналогично, false будет обозначать, что то, что напечатано — ложь. Например, если этот вывод программы такой:
Ниже представлены логические операторы, которые используются в логических выражениях:
Порядок, в котором эти выражения вычисляются, может быть указан с помощью круглых скобок. Так же их можно группировать. Когда выражения в скобках попадают в более сложные выражения, значения этих выражений расчитвается до того, как они будут использованы в выражениях, в которые они попали. Например, это выражение «если там есть кофе или чай, а также печенье или булочка, то я счастлив» может быть запрограммировано примерно так, как указано ниже:
Все значения типа bool, представленные выше, напечатаны как «false» или «true». Но это не работает в обратном направлении: эти строки «false» и «true» не автоматически читаются как значения false и true. По этой причине, эти входные данные должны считываться как строки а затем конвертироваться в значения типа bool.
Поскольку в одном из упражнений ниже нужно, чтоб Вы ввели «false» и «true», я вынужден использовать возможности D, что я не объяснил Вам еще. Я описал ниже метод, который конвертирует указанные строковые входные данные в данные типа bool. Этот метод будет решать эту задачу выполнением to, который продекларирован в модуле std.conv. (Вы можете увидеть ConvException ошибки, если введете что-нибудь, кроме «false» или «true».)
Я надеюсь, что все части кода, которые в main() в следующих программах и понятны на данном этапе. read_bool() это тот метод, в котором есть новые, для Вас, возможности языка. Хотя я вставил комментарии для, чтобы объяснить, что он делает, Вы можете не обращать внимания наэтот метод. Все-таки, он должен быть в коде программы для компиляции и корректной работы.
Логические выражения
Фактическая работа, которую выполняет программа заключается в выражениях. Любая часть программы, которая создает значение или побочный эффект, называется выражением. Оно определяется широким понятием, потому что даже константное значение, скажем 42, и строковое, например «hello», это выражения, поскольку они создают эти соответствующие константы 42 и «hello».
Важно: Не путайте создание значения с декларацией переменной. Значениям не нужно привязываться к переменным.
Вызовы функции, например writeln — это выражения, кстати, потому что у них есть побочные эффекты. В случае с writeln, этот эффект накладывается на стандартный поток вывода печатанием символов на нем. Другим примером из программ, что мы написали ранее, может быть операция присвоения, которая изменяет переменную, которая стоит слева.
Из-за создания значений, выражения могут принимать участие в других выражениях. Это позволяет нам формировать более сложные выражения из более простых. Например, предположим, что есть функция названная currentTemperature, которая возвращает значение текущей температуры воздуха, это значение, что она производит, может быть непосредственно использоваться в выражении writeln:
writeln("It's ", currentTemperature()," degrees at the moment.");
Эта строка содержит следующее:
- «It's»
- currentTemperature()
- " degrees at the moment.
- writeln() выражение, которое использует предыдущие три.
В этой главе мы обсудим конкретные типы выражений, которые используются в условных высказываниях.
Прежде, чем идти дальше я бы хотел повторить оператор присваивания еще раз, сейчас подчеркивая эти два выражения, что находятся на слева и справа от него. Оператор присваивания (=) присваивает значение указанного выражения справа выражению слева (например переменной).
temperature = 23 // temperature's value becomes 23
Логические выражения
Логические выражения — выражения, которые используются в Булевой алгебре. Логические выражения то, что делают компьютерные программы, принимая решения, вроде «если ответ Да, я сохраню файл».
Логические выражения могут иметь одно из двух значений: false, обозначающее ложь, и true, обозначающее истину.
Я буду использовать writeln выражения в следующих примерах. Если строка напечатала true в конце, это будет обозначать, что то, что напечатано в этой строке — это правда. Аналогично, false будет обозначать, что то, что напечатано — ложь. Например, если этот вывод программы такой:
There is coffee: trueэто будет подразумевать, «там есть кофе». Аналогично:
There is coffee: falseбудет подразумевать «там кофе нет». Обратите внимание, что в действительности «is», находящийся слева не обозначает, что кофе есть. Я использую конструкцию "… is …: false" чтоб обозначить «это не так» или «это ложь». Логические выражения используются активно в предикатах, циклах, аргументах функций и т. д. Важно понять, как они работают. К счастью, логические выражения очень простые для объяснения и просты в использовании.
Ниже представлены логические операторы, которые используются в логических выражениях:
- Оператор равенства (==) отвечает на вопрос «это равно этому?». Он сравнивает два выражения слева от него справа и возвращает true, если они равны и false если нет. По сути, значение, возвращаемое оператором равенства (==) — это логическое выражение
Как пример, предположим, что у нас есть указанные две переменные:
Далее, это два логических выражения, которые используют эти значения:int daysInWeek = 7; int monthsInYear = 12;
daysInWeek == 7 // true monthsInYear == 11 // false
- Оператор неравенства (!=) отвечает на вопрос «это не равно этому». Он сравнивает эти два выражения с обеих его сторон и возвращает результаты, противоположные тем, что возвращает оператор (==)
daysInWeek != 7 // false monthsInYear != 11 // true
- Оператор дизъюнкции (||) обозначает «или», и возвращает true если любое из логических выражений равно true
Если значение выражения слева это true, то оператор вернет true и даже не посмотрит на выражение справа. Если выражение слева вернет false, то оператор вернет значение выражения справа. Этот оператор похож на союз «или» в русском языке.
Выражение слева Оператор Выражение справа Результат false || false false false || true true true || false (не имеет значения) true true || true (не имеет значения) true
Потому что по крайней мере одно из двух выражений истинно логическое выражение выше выдает true.import std.stdio; void main() { // false означает "нет", true означает "да" bool existsCoffee = false; bool existsTea = true; writeln("There is warm drink: ", existsCoffee || existsTea); }
- Оператор конъюнкции (&&) обозначает «и» и возвращает true, если оба выражения, слева и справа, возвращают true.
Если значение выражения слева это false, то оператор вернет false и даже не посмотрит на выражение справа. Если выражение слева вернет true, то оператор вернет значение выражения справа. Этот оператор похож на союз «и» в русском языке.Выражение слева Оператор Выражение справа Результат false && false (не имеет значения) false false && true (не имеет значения) false true && false false true && true true - Оператор строгой дизъюнкции (^) отвечает на вопрос «один или другой, но не оба?». Этот оператор возвращает true, если только одно выражение возвращает true, но не оба.
Выражение слева Оператор Выражение справа Результат false ^ false false false ^ true true true ^ false true true ^ true false writeln("I will play chess: ", jimShowedUp ^ bobShowedUp);
- Оператор строго меньше (<) отвечает на вопрос «Это меньше этого?» (или «При сортировке это будет выше?»)
writeln("We beat: ", theirScore < ourScore);
- Оператор строго больше (>) отвечает на вопрос «Это больше этого?» (или «При сортировке это будет ниже?».)
writeln("They beat: ", theirScore > ourScore);
- Оператор нестрого меньше (<=) отвечает на вопрос «Это меньше или равно этому?» (или «При сортировке это будет выше или на той же поцизии?».)
writeln("We were not beaten: ", theirScore <= ourScore);
- Оператор нестрого меньше (>=) отвечает на вопрос «Это больше или равно этому?» (или «При сортировке это будет ниже или на той же поцизии?».)
writeln("We did not beat: ", theirScore >= ourScore);
- Оператор инверсии (!) подразумеват «Это противоложность чего-то». Он отличается от предыдущих операторов тем, что работает только с одним выражением и возвращает true, если выражение возвращает false, и возвращает false, если выражение возвращает true.
writeln("I will walk: ", !existsBicycle);
Группирование выражений
Порядок, в котором эти выражения вычисляются, может быть указан с помощью круглых скобок. Так же их можно группировать. Когда выражения в скобках попадают в более сложные выражения, значения этих выражений расчитвается до того, как они будут использованы в выражениях, в которые они попали. Например, это выражение «если там есть кофе или чай, а также печенье или булочка, то я счастлив» может быть запрограммировано примерно так, как указано ниже:
writeln("I am happy: ", (existsCoffee || existsTea) && (existsCookie || existsScone));
Если эти вложенные выражения не были заключены в скобки, то они будут выполнены с учетом приоритетов операторов по правилам D (которые были унаследованы из языка C). Поскольку у оператора конъюнкции && приоритет выше, чем у оператора дизъюнкции ||, написание выражения без скобок не будет расчитано, как предполагается.writeln("I am happy: ", existsCoffee || existsTea && existsCookie || existsScone);
Оператор конъюнкции && выполнится в первую очередь, и все выражение будет семантически эквивалентно следующему выражению:writeln("I am happy: ", existsCoffee || (existsTea && existsCookie) || existsScone);
Это в корне имеет другое значение: «Если там есть кофе или чай с печеньем или булочка, то я счастлив».Чтение входных данных типа bool
Все значения типа bool, представленные выше, напечатаны как «false» или «true». Но это не работает в обратном направлении: эти строки «false» и «true» не автоматически читаются как значения false и true. По этой причине, эти входные данные должны считываться как строки а затем конвертироваться в значения типа bool.
Поскольку в одном из упражнений ниже нужно, чтоб Вы ввели «false» и «true», я вынужден использовать возможности D, что я не объяснил Вам еще. Я описал ниже метод, который конвертирует указанные строковые входные данные в данные типа bool. Этот метод будет решать эту задачу выполнением to, который продекларирован в модуле std.conv. (Вы можете увидеть ConvException ошибки, если введете что-нибудь, кроме «false» или «true».)
Я надеюсь, что все части кода, которые в main() в следующих программах и понятны на данном этапе. read_bool() это тот метод, в котором есть новые, для Вас, возможности языка. Хотя я вставил комментарии для, чтобы объяснить, что он делает, Вы можете не обращать внимания наэтот метод. Все-таки, он должен быть в коде программы для компиляции и корректной работы.
Упражнения
- Мы видели выше, что эти операторы < и > использованы чтоб определить, когда значение больше и когда меньше другого значения, но там не было оператора, который отвечает на вопрос «это между?», чтоб определить когда значение находится между двумя другими значениями.
Давайте предположим, что программист написал следующий код для определения когда value между 10 и 20. Заметьте, что программа не скомпилируется как описано.
Попробуйте заключить в скобки все это выражение:import std.stdio; void main() { int value = 15; writeln("Is between: ", 10 < value < 20); // ← ошибка компиляции }
Заметьте, что эта программа все равно не скомпилируется.writeln("Is between: ", (10 < value < 20)); // ← ошибка компиляции
- Пока идет поиск решения этой проблемы, тот же программист обнаруживает, что следующие использование скобок позволяет cкомпилировать код:
Заметьте, что программа сейчас работает как предполагалось и выводит «true». К сожалению этот вывод сбивает с толку, потому что в этой программе есть баг. Посмотреть последствия этого бага можно, заменив 15 значением больше 20:writeln("Is between: ", (10 < value) < 20); // ← это пройдет компиляцию, но работает неправильно
Заметьте, что программа все равно выводит «true», несмотря на то, что 21 не меньше 20. Подсказка: Помните, что тип логического выражения это bool. У этого не должно быть смысла, когда bool меньше 20.int value = 21;
- Логические выражения, которые отвечают на вопрос «Это между?» должны, вместо этого, отвечать на вопрос: «Это больше чем минимальное значение и меньше чем максимальное?».
Измените выражение в этой программе с учетом этой логики и заметите, что она сейчас выводит «true», как и ожидалось. Также можно протестировать, что это логическое выражение работает правильно с другими значениями. Например, когда value это 50 или 1, эта программа должна вывести «false» и когда value равно 12, эта программа выведет «true». - Предположим, что мы можем пойти на пляж, когда одно из следующих условий истинно:
- Если расстояние до пляжа меньше 10 км и есть велосипеды для каждого.
- Если нас меньше 6, и у нас есть машина, и у одного из нас есть водительские права.
Введите различные значения и протестируйте это логическое выражение, которое Вы написали, работает правильно.import std.stdio; import std.conv; import std.string; void main() { write("How many are we? "); int personCount; readf(" %s", &personCount); write("How many bicycles are there? "); int bicycleCount; readf(" %s", &bicycleCount); write("What is the distance to the beach? "); int distance; readf(" %s", &distance); bool existsCar = read_bool("Is there a car? "); bool existsLicense = read_bool("Is there a driver license? "); /* Замените это 'true' ниже логическим выражением, которое вернет 'true', когда будет выполнять одно из условий: */ writeln("We are going to the beach: ", true); } /* Пожалуйста обратите внимание на то, что этот метод включает в себя возможности, которые будут описаны в книге позже. */ bool read_bool(string message) { // Выводит сообщение write(message, "(false or true) "); // Читает линию как строку. string input; while (input.length == 0) { input = chomp(readln()); } // Возвращает булево значение из строки bool result = to!bool(input); // Возвращает результат return result; }
… решение
- Поскольку компилятор воспринимает 10 < value уже как выражение, он ждет, что после него будет запятая, чтоб принять его как аргумент для writeln. Использование скобок вокруг всего выражения не сработает, потому что в это время закрывающая скобка будет ожидаться в том же выражении.
- Группировка этого выражения как (10 < value) < 20 удалит ошибку при компиляции, потому что в этом случае первая часть будет рассчитана и далее его результат будет сравниваться с < 20
Мы знаем, что значение логического выражения, такого как 10 < value, будет false или true. false и true принимают значения 0 и 1, соответственно, в целочисленных выражениях. Мы рассмотрим автоматическое преобразование типов в следующих главах. В результате, все это выражение будет эквивалентно либо 0 < 20 либо 1 < 20, которые оба вернут true. - Выражение «больше чем минимальное значение и меньше чем максимальное», может быть запрограммировано следующим образом:
writeln("Is between: ", (value > 10) && (value < 20));
- «Есть ли велосипеды для каждого» может быть запрограммировано как personCount <= bicycleCount или так bicycleCount >= personCount. Остальное в этом логическом выражении может быть сразу переведено в программный код из упражнения:
Обратите внимание на расположение данного оператора дизъюнкции (||) делает чтение удобнее, разделяя эти два основных предиката.writeln("We are going to the beach: ", ((distance < 10) && (bicycleCount >= personCount)) || ((personCount <= 5) && existsCar && existsLicense) );