4. Условия, циклы и граничные значения
Изучите if, for, while и диапазон повторяющихся утверждений.
Wave Foundation
Выберите путь выполнения
Программа из предыдущей главы выполняла операторы сверху вниз. Настоящая программа должна делать разные вещи в зависимости от входных данных и состояния. Условные операторы выбирают путь выполнения, а циклы применяют одно и то же правило к нескольким значениям.
Сохраните каждый пример в main.wave и запустите его. При чтении кода запишите на листе бумаги текущие значения переменных, условия, которые будут проверяться дальше, и порядок выполнения операторов. Гораздо важнее тренироваться следовать потоку, чем запоминать результаты.
if и else
Условия пишутся в круглых скобках, а текст заключается в фигурные скобки. В следующем примере замените balance на 500 или 2000, чтобы определить, какая ветвь выполняется.
fun main() {
var balance: i32 = 2000;
var price: i32 = 1200;
if (balance >= price) {
balance -= price;
println("bought, balance={}", balance);
} else {
println("not enough money");
}
}
Результат выполнения:
bought, balance=800
Оба блока не выполняются. Если условие истинно, выполняется первый блок. Если условие ложно, выполняется блок else. Покупки разрешены, даже если balance равен price, поэтому я написал >=. Если вы измените его на >, операция изменится на ту же сумму.
Порядок нескольких условий
Вы можете объединить условия с помощью else if. Поскольку сначала мы выполняем одну удовлетворенную ветвь сверху, нам нужно решить, хотим ли мы сначала проверить большую границу или меньшую границу.
fun grade(score: i32) {
if (score < 0 || score > 100) {
println("invalid");
} else if (score >= 90) {
println("A");
} else if (score >= 80) {
println("B");
} else {
println("C");
}
}
fun main() {
grade(95);
grade(80);
grade(79);
grade(101);
}
Результат выполнения:
A
B
C
invalid
Недействительные оценки сначала отклоняются, а затем оцениваются. Если вы поставите score >= 80 в начале, вы никогда не дойдете до ветки A, потому что в эту ветку входит 95 градусов. Проверьте порядок условий, а также правильность каждого условия.
Не меняйте значения в условных выражениях
Операции присваивания, составного присваивания, а также увеличения или уменьшения не допускаются в условиях if, while или for. Используйте == для сравнения. Чтобы обновить значение и затем проверить его, напишите два отдельных оператора.
Правильная форма фрагмента внутри функции:
value = read_value();
if (value == expected) {
println("matched");
}
read_value и expected не определены в этом фрагменте, поэтому это не полная программа, которая работает как есть. Здесь показано правило: «Сравнить после изменения состояния».
while: Пока условия сохраняются
fun main() {
var remaining: i32 = 3;
while (remaining > 0) {
println("{}", remaining);
remaining -= 1;
}
println("finished at {}", remaining);
}
Результат выполнения:
3
2
1
finished at 0
Условия проверяются перед входом в кузов. Если remaining с самого начала равен 0, тело никогда не выполняется. Если декремент в конце тела опущен, условие остается истинным и цикл не завершается.
После написания цикла проверьте «Что приближает его к условию завершения?» Если это цикл, ожидающий ввода, его роль играет изменение ввода или EOF, а если это числовой цикл, свою роль играет обновление индекса.
for: Инициализация/Условия/Обновление
for обозначает три части, необходимые для повторения.
fun main() {
var total: i32 = 0;
for (var number: i32 = 1; number <= 5; number += 1) {
total += number;
}
println("sum={}", total);
}
Результат выполнения:
sum=15
- Инициализируйте number значением 1. Этот шаг выполняется один раз.
- Проверяет number <= 5. Если ложно, завершить итерацию.
- Добавьте в текст от number до total.
- Увеличьте number на 1 и вернитесь к проверке состояния.
Не предполагается, что переменные повторения, объявленные в for, могут использоваться после повторения. Если ваш проект требует значения после итерации, объявите его снаружи и четко укажите местоположение инициализации.
Границы включения и исключения
Натуральная сумма от 1 до 5 равна <= 5. С другой стороны, индекс массива длиной 5 должен использовать < 5. Это связано с тем, что индексы массива начинаются с 0 и заканчиваются 4.
Не путайте «выполнить пять раз» с «до значения 5 включительно». Определить количество повторений можно, посмотрев одновременно начальное и конечное значения. Случаи, когда входные данные пусты и содержат только один элемент, хороши для обнаружения ошибок границ.
continue и break
continue пропускает оставшуюся часть этой итерации, а break завершает ближайшую итерацию.
fun main() {
var total: i32 = 0;
for (var number: i32 = 1; number <= 10; number += 1) {
if (number == 3) {
continue;
}
if (number == 6) {
break;
}
total += number;
}
println("{}", total);
}
Результат выполнения:
12
Общее число: 1, 2, 4 и 5. Если continue встречается в for, процесс обновления продолжится. Поскольку while не имеет отдельного выражения обновления, такого как for, вы должны быть осторожны, чтобы не пропустить какие-либо изменения состояния, необходимые до continue.
Если циклы вложены, один break не завершает все циклы. Если вам нужно остановиться на нескольких этапах, заключите работу в функцию и укажите свое намерение, используя return или также проверив условие завершения во внешней итерации.
Разделите падеж на match
Вы можете использовать match при сравнении нескольких вариантов одного и того же значения. Тело каждого arm представляет собой блок.
fun describe(status: i32) {
match (status) {
200 => {
println("ok");
}
404 => {
println("missing");
}
_ => {
println("other");
}
}
}
fun main() {
describe(200);
describe(404);
describe(500);
}
Результат выполнения:
ok
missing
other
_ — это шаблон, который обрабатывает все остальное. Не размещайте дубликаты внутри одного и того же match. variant, который имеет разные типы данных в зависимости от значения, описан в Глава модели данных.
Полный пример: подсчет чисел, соответствующих условиям
Найдите количество и сумму четных чисел от 1 до 10. Поскольку количество и сумма — это разная информация, они накапливаются как переменные.
fun main() {
var count: i32 = 0;
var total: i32 = 0;
for (var number: i32 = 1; number <= 10; number += 1) {
if (number % 2 == 0) {
count += 1;
total += number;
}
}
println("count={} total={}", count, total);
}
Результат выполнения:
count=5 total=30
Четные числа — 2, 4, 6, 8 и 10, поэтому число — 5, а сумма — 30. Даже если выражение короткое, границу итерации легко проверить, если сначала проверить результат в небольшом диапазоне, который можно получить вручную.
Упражнение и полное решение
Добавляйте только числа, кратные 3, от 1 до 20, но не добавляйте значения, сумма которых превышает 30. Нам нужно различать «добавление, а затем проверка, закончилось ли оно» и «проверка, закончилось ли оно, а затем добавление».
fun main() {
var total: i32 = 0;
for (var number: i32 = 1; number <= 20; number += 1) {
if (number % 3 != 0) {
continue;
}
if (total + number > 30) {
break;
}
total += number;
}
println("{}", total);
}
Результат выполнения:
30
Значения 3+6+9+12 в сумме дают 30, поэтому следующее значение, 15, не добавляется. Эти небольшие входные данные безопасны, но для больших целых чисел проверка total + number может сама переполниться. Написание проверки не обрабатывает автоматически каждый граничный случай.