Изменения

Материал из Chaotic Onyx
Перейти к навигацииПерейти к поиску
Перевод части оригинального гайда по DM "Операторы циклов". Не претендую на полную точность перевода.
Строка 610: Строка 610:     
= Операторы циклов =
 
= Операторы циклов =
 +
 +
Существует множество способов выполнить один и тот же блок кода несколько раз в последовательности. Это называется циклом, потому что точка выполнения перемещается вниз по блоку кода, а затем прыгает обратно наверх, чтобы выполнить все сначала. Любая форма цикла включает в себя некоторый способ его завершения; в противном случае он будет продолжаться вечно. Обычно это делается в виде булева условия, которое должно выполняться при каждом повторении цикла.
 +
 +
Каждый вид цикла удобен в разных ситуациях. Синтаксис и применение каждого вида будут описаны в следующих разделах.
 +
 +
== for цикл списка ==
 +
 +
Одна из очень распространенных задач в программировании DM - выполнение некоторой операции над каждым элементом списка. Для этой цели предназначен цикл for.
 +
 +
for(variable as input-type in list) Statement
 +
 +
Операторы внутри цикла for являются его телом. Синтаксис для определения тела цикла такой же, как и для оператора if. Одно утверждение может быть включено в одну строку или несколько утверждений могут быть помещены в блок с отступом под утверждением for.
 +
 +
Каждый элемент указанного списка, имеющий указанный тип ввода, поочередно присваивается заданной переменной. После каждого присваивания выполняется тело цикла for. Один проход по циклу for (или любому другому) называется итерацией. Весь процесс часто называют «перебором или просмотром списка».
 +
 +
(Математики и компьютерщики не обращают внимания на предлоги и часто просто выбирают их наугад, чтобы удовлетворить свои цели. Например, после того как я наконец-то принял утверждение «f из x - это карта из вещественной области на область f». я обнаружил, что оставшаяся часть исчисления относительно проста.)
 +
 +
Обратите внимание, что синтаксис цикла for очень похож на синтаксис определения аргумента verb. Вводится переменная, в которой будет храниться значение из списка, а все значения, не относящиеся к нужному типу, отфильтровываются. Единственное отличие заключается в том, что переменная цикла for не определяется в этом операторе. Она должна быть определена в предыдущем коде.
 +
 +
В цикле for можно использовать те же типы входных данных, что и в определении аргумента. Полный список см. в разделе 4.5.1. Несколько типов можно использовать в комбинации с помощью оператора |.
 +
 +
(Кстати, теперь вы должны понять, почему в этом случае используется |. Каждый тип ввода - это фактически битовый флаг, который может быть объединен побитовым ИЛИ.)
 +
 +
Как и в случае с определением аргументов, для типа ввода и списка задаются удобные значения по умолчанию. Если тип ввода не указан, все элементы, не соответствующие типу переменной, автоматически отсеиваются. Если список не указан, то по умолчанию используется содержимое всего мира (world.contents или просто world). Это отличается от аргументов verb, которые по умолчанию используют список view().
 +
 +
В теле цикла for переменная цикла, конечно же, будет использоваться каким-либо образом. Например, список инвентаря может быть выведен путем перебора каждого предмета из содержимого игрока.
 +
 +
mob/verb/inventory()
 +
    var/obj/O
 +
    usr << "You are carrying:"
 +
    for(O in usr)
 +
      usr << O.name
 +
 +
Оператор мог бы быть for(O as obj in usr), но это было бы излишним в данном случае, поскольку мы определили переменную для этого типа.
 +
 +
Один тонкий момент возникает, когда вы изменяете содержимое списка, по которому выполняется цикл. Например, могут возникнуть ситуации, когда вы хотите, чтобы игрок сбросил все, что есть в инвентаре.
 +
 +
mob/verb/strip()
 +
    var/obj/O
 +
    for(O in usr)
 +
      O.loc = usr.loc  //drop it
 +
 +
Это действительно будет работать, как и ожидалось. Если бы пришлось выполнять всю работу по прямому просмотру списка (что вы увидите в разделе 10.2), то в подобных случаях было бы легко ошибиться, поскольку содержимое списка меняется с каждой итерацией. DM справляется с подобными ситуациями, создавая временную копию списка в начале цикла for.
 +
 +
Однако есть один список, который DM считает слишком громоздким, чтобы работать с ним таким образом, - это список world.contents. Не перебирайте содержимое всего мира, если вы одновременно изменяете этот список (т. е. создаете или уничтожаете объекты). Это не всегда будет работать так, как вы ожидаете. При необходимости вы можете создать собственную временную копию списка, используя приемы, описанные в главе 10.
 +
 +
== for условный цикл ==
 +
 +
Существует вторая форма цикла for. Вы можете считать его ручной версией; вы можете использовать его для цикла по списку, но он не будет автоматически обрабатывать этот процесс за вас, как другой синтаксис. Преимущество в том, что с его помощью вы можете делать все, что хотите, и так, как хотите.
 +
 +
for(initialization; condition; iteration) Statement
 +
 +
Цикл for состоит из трех частей: оператора инициализации, условного выражения и оператора итерации. Оператор инициализации выполняется один раз перед началом любой итерации. Затем в начале каждой итерации проверяется условие. Если оно ложно, цикл for завершается. В противном случае выполняется тело цикла for. (Это может быть блок из нескольких операторов.) Наконец, в конце тела цикла выполняется оператор итерации, проверяется условие, и процесс повторяется до тех пор, пока условие не станет ложным.
 +
 +
(Некоторые из вас узнают в этом цикл for в стиле C. Однако будьте осторожны, не используйте запятую, как это делается в C, чтобы упаковать несколько операторов в один управляющий оператор цикла. В DM запятая в этом контексте идентична точке с запятой. Чтобы упаковать несколько операторов вместе, их следует окружить скобками { }.)
 +
 +
Предположим, например, что вы хотите создать переменное количество объектов. Самым простым способом будет использование цикла for.
 +
 +
obj/scroll/medicine
 +
    verb/cast(N as num)
 +
      var/i
 +
      for(i=1; i<=N; i++)
 +
          new/obj/medicine(usr)
 +
 +
Этот пример определяет свиток медицины, который позволяет игроку создавать столько лекарств, сколько он пожелает. (Возможно, вы захотите встроить стоимость одного лекарства, вычитая из магической силы игрока или что-то в этом роде). Новая команда будет подробно описана в разделе 7.2. Она создает объект указанного типа в заданном месте. В данном случае местоположение - это инвентарь пользователя.
 +
 +
== цикл while ==
 +
 +
Цикл while - это более простая версия цикла for. Он принимает только параметр условия и оставляет инициализацию и управление итерациями на усмотрение остальной части кода. Как и в цикле for, условие проверяется в начале каждой итерации. Если оно ложно, цикл завершается.
 +
 +
while(condition) Statement
 +
 +
Этот цикл полезен в основном в ситуациях, когда операторы инициализации и итерации не нужны или могут быть объединены с условием. Например, пример с циклом for может быть реализован с помощью простого цикла while.
 +
 +
obj/scroll/medicine
 +
    verb/cast(N as num)
 +
      while(N-- > 0)
 +
          new/obj/medicine(usr)
 +
 +
Это дает точно такой же эффект, как и создание N объектов-лекарств, но делает это по-другому. Когда вы познакомитесь с операторами увеличения и уменьшения, компактный код, подобный этому, может показаться более привлекательным. В противном случае можно было бы, очевидно, уменьшить N в нижней части тела цикла while.
 +
 +
== Цикл do while ==
 +
 +
Цикл do while похож на цикл while, за исключением того, что условие проверяется в конце итерации, а не в начале. Это гарантирует, что тело цикла будет выполнено хотя бы один раз. В некоторых ситуациях это как раз то, что нужно.
 +
 +
do
 +
    Statement
 +
while(condition)
 +
 +
Например, можно сделать так, чтобы verb medicine работал вообще без аргументов (когда игрок спешит за лекарством).
 +
 +
obj/scroll/medicine
 +
    verb/cast(N as num|null)
 +
      do
 +
          new/obj/medicine(usr)
 +
      while(--N > 0)
 +
 +
Теперь можно просто набрать «(cast medicine)», чтобы создать один объект лекарства. То же самое можно было бы сделать и с аргументом по умолчанию, равным 1.
    
= Перемещение по коду =
 
= Перемещение по коду =
    
= Оператор выбора =
 
= Оператор выбора =
33

правки

Навигация