Изменения

Перевод части оригинального гайда по DM "Перемещение по коду". Не претендую на полную точность перевода.
Строка 710: Строка 710:     
= Перемещение по коду =
 
= Перемещение по коду =
 +
 +
Цикл и условные операторы существуют потому, что они обеспечивают структурированный синтаксис для очень распространенных операций. Однако иногда они могут не совсем соответствовать вашим требованиям. Существует несколько менее структурированных инструкций, которые помогут вам адаптировать другие операторы потока управления к любым возможным целям. Они описаны в следующих разделах.
 +
 +
== Операторы break и continue ==
 +
 +
Операторы break и continue используются для завершения всего цикла или текущей итерации цикла, соответственно. Они полезны, когда возникает ситуация, не подходящая ни под один из простых операторов цикла. Они помещаются в тело цикла - обычно внутри оператора if, который должен быть выполнен при выполнении некоторого условия.
 +
 +
Можно использовать оператор continue при перечислении всех игроков в игре, чтобы не включать пользователя в список.
 +
 +
mob/verb/who()
 +
  var/mob/M
 +
  for(M in world)
 +
  if(!M.key) continue //skip NPCs
 +
  if(M == usr) continue //skip self
 +
 +
  if(M.name == M.key) usr << M.name
 +
  else usr << "[M.name] ([M.key])"
 +
 +
Это отображает всех других игроков (и их настоящее имя ключа, если они используют псевдоним). Конечно, этот пример можно переписать и без continue, изменив порядок утверждений. Однако в более сложных ситуациях использование continue и break иногда может значительно прояснить код.
 +
 +
== оператор goto ==
 +
 +
Оператор goto заставляет выполнить переход к указанной метке в коде.
 +
 +
goto label
 +
.
 +
.
 +
.
 +
label
 +
 +
Метка - это просто узел, обозначающий точку назначения в коде, и может предшествовать или следовать за оператором goto. Аргумент оператора goto - это путь к узлу назначения. В качестве удобства перед этим путем ставится неявная точка. Это означает, что в большинстве случаев вам нужно указать только имя метки и никакой дополнительной информации о пути. См. раздел 6.15.2 об операторах пути.
 +
 +
Оператор goto следует использовать только тогда, когда он проясняет код. В большинстве ситуаций предпочтительнее использовать более структурированные циклы и условные операторы. Одна из ситуаций, в которой goto может оказаться полезным, - это когда перед возвратом из процедуры необходимо выполнить некоторый завершающий код, а в остальной части процедуры есть несколько точек, в которых необходимо завернуть код и вернуться. Вместо того чтобы повторять один и тот же код сворачивания везде (и, возможно, забывать сделать это в некоторых местах), вы можете поместить его в нижнюю часть процедуры с меткой перед ним.
 +
 +
Привести простой пример невозможно, поскольку в любой простой ситуации вы не захотите использовать goto. Однако общая структура будет выглядеть примерно так:
 +
 +
proc/Example()
 +
    //Complex code with the occasional:
 +
    goto wrapup
 +
 +
    //Final code that goes straight down to wrapup
 +
    //unless it returns.
 +
 +
    wrapup:
 +
    //Do wrapup stuff here.
 +
 +
Как показано в этом примере, в конце метки можно поставить необязательное двоеточие. Это помогает отличить узел от других утверждений. Кроме того, это стандартный способ объявления меток в большинстве языков программирования.
 +
 +
Важно пояснить, что метка в коде ничего не делает. Это просто маркер. Если выполнение достигает метки, оно сразу переходит к следующему оператору.
 +
 +
== Метки для блоков ==
 +
 +
В предыдущем разделе вы узнали, как обозначить точку в коде процедуры и перейти к ней. Это очень гибкая техника, но ей не хватает структуры, поэтому исходный код может получиться запутанным и сложным для понимания. Иногда вы можете захотеть объединить функциональность goto с инструкциями цикла break и continue. Для этого нужно использовать метки блоков.
 +
 +
Метка блока - это то же самое, что и метка goto, за исключением того, что она размещается в верхней части блока кода с отступом. Как и метка goto, метка блока ничего не делает. Выполнение пропускается мимо нее и начинается с первого оператора в блоке. Метку блока можно даже использовать в качестве адресата оператора goto. Однако на самом деле она используется в операторах break и continue.
 +
 +
И break, и continue по умолчанию работают с самым внутренним циклом, содержащим их. Однако если указано имя блока, то они применяются к этому блоку. Оператор break приводит к переходу к концу блока; continue вызывает следующую итерацию цикла, непосредственно содержащегося в блоке.
 +
 +
В следующем примере используется блок с метками для кражи еды у людей.
 +
 +
obj/scroll/free_lunch/verb/cast()
 +
    var/mob/M
 +
    var/obj/food/F
 +
 +
    victim_loop:
 +
      for(M in view())
 +
          if(M == usr) continue victim_loop
 +
          for(F in M)
 +
            M << "Thanks for the contribution!"
 +
            F.loc = usr  //grab the snack
 +
            continue victim_loop
 +
          usr << "[M] has nothing to offer."
 +
 +
В этом примере есть два цикла, внешний и внутренний. Во внешнем цикле перебираются все существа, находящиеся в поле зрения пользователя. Он был обозначен как victim_loop. Первый оператор continue используется для того, чтобы не дать пользователю украсть свою еду. Он будет работать как с меткой victim_loop, так и без нее, поскольку это цикл, непосредственно содержащий оператор continue.
 +
 +
Внутренний цикл перебирает продукты, которые несет жертва. Обратите внимание, что это не совсем цикл, потому что в конце самой первой итерации он продолжает внешний цикл. Это обычный трюк, используемый для поиска первого элемента, полученного от заданного типа (в данном случае /obj/food). В данном случае необходимо было явно использовать метку victim_loop, поскольку в противном случае continue применялось бы к внутреннему циклу, а не к внешнему. Это привело бы к тому, что заклинание оказалось бы слишком жадным и украло бы всю еду каждой жертвы, а не только по одному предмету.
    
= Оператор выбора =
 
= Оператор выбора =
33

правки