Приветствую. С вами я, Deimos, и сегодня я хотел бы попробовать рассказать Вам о том, что же такое return, как его правильно использовать и что с помощью него можно провернуть.
Начать стоит с определений. Для начала определимся, что же такое "оператор".
Оператор — это часть программы, которая может быть выполнена отдельно.
Это означает, что оператор определяет некоторое действие.
Другими словами можно сказать, что оператор - это своеобразная команда для скрипта, предписывающая определённую реакцию этого самого скрипта на её (команды) вызов
Оператор возврата
«Return»это оператор управления (оператор перехода),обеспечивающий немедленный выход из функции.
* Данный оператор имеет два важных применения:
Во-первых, как было сказано выше, он обеспечивает немедленный выход из функции, т.е. заставляет виртуальную машину передать управление коду, вызвавшему функцию.
Во-вторых, этот оператор можно использовать для того, чтобы возвратить определённое значение в код (функцию), из которого была вызвана текущая, прерванная функция.
* Формат оператора return
PHP код:
return значение; //Где "значение" является необязательным
• Для чего же нужен этот выход из функции:
Прежде всего, с помощью данного оператора, мы можем управлять действиями виртуальной машины при выполнении кода. Например, нам не нужно выполнять определённый код функции, если у игрока нет на руках 5000$. Тут то нам и придёт на помощь данный оператор. Но это ещё не всё.
Оптимизация.
Допустим, у нас есть подобный, не самый качественный в плане структуры, код команд
А вот как код должен выглядетьPHP код:
public OnPlayerCommandText(playerid, cmdtext[])
{
if(!strcmp("/команда_1", cmdtext, true))
{
SetPlayerHealth(playerid, 98304);
SendClientMessage(playerid, 0xFF0000FF, "Теперь ваше здоровье мигает :3");
}
if(!strcmp("/команда_2", cmdtext, true))
{
printf("Продам гараж");
}
if(!strcmp("/команда_3", cmdtext, true))
{
Ban(playerid);
}
if(!strcmp("/команда_4", cmdtext, true))
{
Kick(playerid);
}
return 1;
}
Но эти оба варианта будут работать практически одинаково (не считая того, что в первом случае мы вернули в колбэк единицу, дабы избавиться от сообщения "Unknown command" (О реакции некоторых колбэкков на возвраты поговорим чуть позже) и того, о чём я напишу дальше), тогда в чём разница, спросите Вы?PHP код:
public OnPlayerCommandText(playerid, cmdtext[])
{
if(!strcmp("/команда_1", cmdtext, true))
{
SetPlayerHealth(playerid, 98304);
SendClientMessage(playerid, 0xFF0000FF, "Теперь ваше здоровье мигает :3");
return 1;
}
else if(!strcmp("/команда_2", cmdtext, true))
{
printf("Продам гараж");
return 1;
}
else if(!strcmp("/команда_3", cmdtext, true))
{
Ban(playerid);
return 1;
}
else if(!strcmp("/команда_4", cmdtext, true))
{
Kick(playerid);
return 1;
}
return 0;
}
А разница именно в том, что в первом случае, найдя команду и выполнив её код, мы не сигнализируем виртуальной машине (серверу) о том, что он нашёл весь код, который нам нужно было найти (в данном случае код, расположенный в блоке условия (команду)). А раз мы не дали чётких указаний по поводу того, где нужно остановить выполнение кода, виртуальная машина продолжит перебирать весь код, расположенный в колбэке (до скобки закрытия блока колбэка), ведь машина не знает Ваших мыслей и выполняет всё так, как указали ей Вы.
Во втором же случае мы:
- Составили правильно условия.
- Указали компилятору "границы" каждого из условий с расчётом на то, что, после выполнении команд, никакого другого нужного кода в блоке колбэка (ниже нашей команды) нет и что нужно выполнить код именно до этой самой "границы".
Всем этим мы освободили виртуальную машину от выполнения ненужных действий (в первом случае, даже после нахождения нужной команды, АМХ машина продолжил бы выполнение условий, продолжая поиск уже найденной команды), следовательно АМХ машина быстрее разберётся с кодом команды и быстрее начнёт обрабатывать другой код. Это и называется оптимизацией ;)
Читабельный вид.
Иными словами, данный оператор позволяет формировать проверки в более понятный для скриптера вид. Согласитесь, гораздо удобнее понять смысл такого условия
PHP код:
if(!IsPlayerConnected(playerid)) return printf("Игрок с ID %d оффлайн", playerid);
Нежели такой
Ведь мы сразу видим, что если игрок не в сети, будет отправлено сообщение в консоль. Во втором же варианте нам придётся просматривать весь код функции и выискивать скобку, отвечающую за "закрытие" блока нашего условия и уже смотреть на действие, которое мы указали после оператора else.PHP код:
if(IsPlayerConnected(playerid))
{
if(любое другое условие)
{
//Тут ещё куча других условий/функций
}
}
else
{
printf("Игрок с ID %d оффлайн", playerid);
return 1;
}
//Данный код может иметь так же сокращённый вариант
//else return printf("Игрок с ID %d оффлайн", playerid);
• Для чего же нужно возвращать определённые условия и какой с этого толк:
Возможность вернуть из одной функции, вызванной в блоке другой функции определённое значение в разы облегчает работу с кодом, позволяя обходится гораздо меньшими ненужными действиями и не забивать память лишними переменными.
Представим следующую ситуацию: есть определённая функция А, в которой выполняется код и, дабы сделать код более читабельным/для удобства или по какой-то ещё причине, определённый кусок кода помещён в другую функцию, созданную самим скриптером. Назовём её функцией "Б". Так вот, у нас есть функция А и функция Б, которая вызывается в функции А. В этой функции Б выполняются определённый код, от которого зависит выполнение кода в функции А. Это могут быть проверки или расчёт каких-то значений. Это не так важно. А важно то, что каким-то образом нам нужно передать полученные данные из функции Б в функцию А. Мы можем создать глобальную переменную, в которую поместим полученные данные из функции Б и пусле будем использовать их в функции А, но это лишние байты памяти (напомню, для всех глобальных переменных уже при компиляции резервируется определённое число байт в памяти АМХ машины) и лишние действия. Тут то к нам на помощь и приходит возможность оператора возврата возвращать определённые значения. Давайте я покажу Вам, для наглядности, примеры кода обоих ситуаций
Таким образом мы облегчили жизнь себе и серверу, не забивая его статическую память лишней информацией, а лишь забивая динамическую (память стэка. С этим тоже стоит быть аккуратнее, не возвращая длинные строковые значения и тому подобное. Об этом есть хороший мануал от Tracker1).
Но перемещение определённого куска кода в отдельную функцию и возврат значения - не единственная прелесть особенности return. С помощью данной особенности можно создавать определённые проверки, которые после можно использовать в более укороченном варианте в любой части кода. Все стандартные функции, позволяющие создавать те или иные проверки, работают именно по этому принципу. Приведу пример одной самописанной проверки:
Таким образом если в строке обнаружится символ, который не проходит по первому условию в case, функция вернёт нуль. Иначе единицу. На основе этой информации мы можем построить проверку где-то в другом участке скрипта. например:PHP код:
stock IsValidText(const text[])//Создаём функцию, аргументом которой будет являться массив для текста
{
for(new i, j = strlen(text); i < j; i++)//Запускаем цикл, число инерций которого будет равно числу символов в нашем аргументе
{
switch(text[i])//Проверяем каждый символ на наличие:
{
case 48..57, 'a'..'z', 'A'..'Z': continue;//Если символ в строке цифра, либо английская буква - начнём следующий такт
default: return 0;//Если символ не является цифрой/буквой - вернём нуль
}
}
return 1;//Если цикл прошёл нормально (в строке были только английские буквы и символы. То бишь каждый такт цикла прекращался на первой проверке), вернём единицу
}
Таким способом можно создавать любые проверки, объединяя уже существующие в одну. Если кто до сих пор не понял, вернуть мы можем любое значение и уже опираясь на знаниях того, какое значение при какой ситуации возвращается, мы строим дальнейшие проверки.PHP код:
public OnPlayerText(playerid, text[])
{
if(!IsValidText(text))//Если наша функция вернёт нуль, покажем сообщение и прервём выполнение паблика
{
SendClientMessage(playerid, 0xFF0000FF, "В строке обнаружен запрещённый символ");
return 0;
}
return 1;
}
Теперь настало время поговорить о том, как реагируют стандартные колбэки на возвраты тех или иных значений. Для более удобного восприятия я создам таблицу
Все остальные события не имеют особой привязки к возвращаемым значениям, разница лишь в том что:
Наименование колбэков: Значение: Реакция на возврат: Порядок обработки:
OnPlayerCommandText 1
0Полное обрывание события.
Скрипт передается во все скрипты, после обработки всеми скриптами выводиться собщения 'SERVER: Unknown command'.Филтрскрипты, гейммод.
OnPlayerText 1
0Обрывание события, сообщение выводится в чат.
обрывание события, сообщение не выводиться в чат и не обрабатывается остальными скриптами, полное обрывание.Филтрскрипты, гейммод.
OnPlayerUpdate 1
0Нормальный режим игры.
Рассинхронизация игрока: для всех игрок стоит на месте, с момента последнего полученного синхронизированного пакета, для него все по прежнему.Филтрскрипты, гейммод.
OnRconCommand 1
0Обрывание события, команда передается в косноль, на этом обрывается.
Обрывание события, передается во все скрипты.Филтрскрипты, гейммод.
OnPlayerRequestSpawn 1
0Спавн игрока.
При нажатии на Shift ничего не происходит.Филтрскрипты, гейммод.
OnPlayerKeyStateChange 1
0Обрабатывается всеми скриптами.
Обрабатывается только гейммодомГейммод, филтрскрипты. (!)
1 - событие полность обрывается.
0 - событие передается и обрабатывается всеми скриптами.
Автор информации о реакции пабликов на возвраты - Stepashka
Таким образом, при возвратах в данных колбэках, нужно учитывать эти данные, дабы получить желаемый результат.
• Возврат функций:
Так же стоить заметить, что и функции возможно вернуть в качестве значения. Точнее значение функции, которое она возвращает.
Покажу на примере:
В предыдущем пункте мы говорили о реакции стандартных колбэков на определённые значения и при возврате функции надо учитывать какое значение эта функция возвращает.PHP код:
main()
{
printf("Функция 1 (25-18) == %d", FuncOne());//В итоге получим 7
printf("Функция 2 (20+5) == %d", FuncTwo());//Во второй функции у нас получится 25
printf("Функция 3 (20) == %d", FuncThree());//Третья функция вернёт значение 20
}
stock FuncOne()
{
return FuncTwo()-18;
}
stock FuncTwo()
{
return 5 + FuncThree();
}
stock FuncThree()
{
return 20;//Третья функция вернёт 20
}
Даже стандартные функции возвращают определённые значения. Чему равны эти значения - можно узнать на сайте wiki.sa-mp.com, поискав нужную Вам функцию и посмотрев её описание.
На этом всё =)
Если есть какие-либо вопросы, если что-то непонятно объяснено или есть какие-либо дополнения/исправления для данного урока, прошу написать об этом ниже.
Всем постараюсь помочь, все мнения приму к сведению.
Версия урока не окончательная и со временем возможны дополнения/исправления.
С вами был DeimoS. Спасибо за вниманиеАвтор урока - DeimoS
Специально для портала Pro-pawn.ru
При копировании данного материала, обязательно указывайте автора и ссылку на данный урок