Добрый всем день. В этой теме я собираюсь продолжить начатую в этой теме серию моих уроков и рассказать вам о функциях.
В каждом нашем скрипте (да и по сути в любой программе на любом языке программирования) встречаются случаи, когда одну и туже последовательность действий необходимо выполнить несколько раз в разных местах. И в итоге эта последовательность выдает нам уже завершенный результат.
Что же такое функция? Функция - скопление действий. Она принимает аргументы, выполняет с ними некоторые действия, и возвращает уже обработанный результат. К примеру, Сварить варенье - функция принимающая аргументы в виде Фруктов, сахара, воды и еще многого чего, и возвращающая варенье. К слову, функция может возвращать любой тип данных, будь то целое число, дробное число, булев тип или строка. При помощи функций так же можно упростить код скрипта.
Code
public Имя_Функции(аргументы) // Что такое public, stock и когда можно вообще ничего не писать перед именем функции вы узнаете ниже.
Имя функции может содержать латинские буквы, цифры, знак пробела. Начинаться с цифры функция не должна. К слову, тоже самое и с названиями переменных.
Выше я применил термины аргумент и параметр. Что же это такое?
Аргумент - неопределенные данные, которые входят в функцию. Параметр - определенные (известные) данные.
Не понятно?
Когда мы описываем функцию, в ее скобках мы указываем аргументы. А когда вызываем ее - параметры.
Приведу пример простой функции. Функция принимает два аргумента, складывает их, умножает на два и выводит ответ в консоль.
Что должно произойти? Мы создали переменную Key со значением 50. Вывели ее значение в консоль. Вызвали функцию Test с параметром Key, в которой присвоили этому параметру Key значение 1000 и вывели результат в консоль. После выполнения функции опять вывели значение Key в консоль.
Как вы думаете, что же получиться в консоли? Если вы думаете, что в консоли будет текст вида
Code
50 1000 1000
то вы неправы. Все дело в том, что существует
Область видимости
В консоли будет отнюдь не
Code
50 1000 1000
В консоли будет 50 1000 50 Как же так? Мы ведь собственноручно вызвали функцию Test, которая присвоила переменной Key значение 1000!
Функция представляет из себя маааленькую программку.
У этой программки есть свои переменные, а переменные из основной программы она просто не видит.
Так как в эту программку одним из параметров поступила переменная Key со значением 50, это значит что функция вполне ее видела и могла с ним работать. Но на самом деле в функцию передаётся на переменная, а её точная копия, то есть... Ее значение. Поэтому когда наша программка (функция) завершает свое выполнение - все её переменные (копии наших, основных) удаляются.
Передача параметров по ссылке
В примере выше, переменная используемая в функции называется локальной (их может быть бесконечно). Локальная переменная - переменная которая создана, изменяется, удаляется в самой функции, а за пределами функции ее не видно.
Для того, что бы передать функции не значение переменной, а саму переменную, изменения которой будут видны и за пределами функции, существует особый способ. Для этого, перед аргументом функции надо поставить знак амперсайд (&), например, вот так:
Теперь, при вызове этой функции с одним-единственным параметром Key, в функцию передастся не значение переменной, а сама переменная. Что это значит? Это значит, что в консоли после кода
При вызове функции без параметра по ссылке, в функцию передается значение переменной, она ее обрабатывает, выдает результат, но переменная вне функции не изменяется. Она остается прежней. При передаче параметра по ссылке, в функцию передается сама переменная, она ее обрабатывает, выдает результат, и изменения которые произошли с переменной в функции видны и вне функции.
Оператор функции - return
Оператор return управляет тем, что функция возвращает. Например, мы напишем такую функцию:
Code
stock IsPlayerRich(playerid) { if(GetPlayerMoney(playerid) > 1000000) return 1; // Если игрок имеет более 1 млн, то возвращаем return 1 или return true; else return 0; //или return false; }
Теперь, мы можем вызвать эту функцию откуда угодно, и основываясь на ее действиях (применяя ветвление, о коем я вам рассказывал в предыдущем уроке) выполнить определенный код. Например, вызовем функцию из OnPlayerDisconnect(playerid)
Code
OnPlayerDisconnect(playerid) { if(IsPlayerRich(playerid)) // Если у игрока больше 1 млн. денег (функция вернет return 1) { SendClientMessageToAll(COLOR_LIGHTRED, "От нас ушел богатый игрок!"); } else SendClientMessageToAll(COLOR_LIGHTRED, "От нас ушел игрок!"); return 1; }
Прокомментирую. Код if(IsPlayerRich(playerid)) проверяет, возвращает ли функция положительное число ( больше нуля). Если да, то мы пишем "От нас ушел богатый игрок!", если нет, то "От нас ушел игрок!"
Кстати, проверить возвращает ли функция ноль, можно так if(!IsPlayerRich(playerid)). Символ ! указывает на отрицание.
Функция не обязательно должна возвращать что-либо. Например, наша функция Test просто выводит в консоль результат своей работы. В случае, если функция ничего не возвращает (нет оператора return), компилятор вернет значение Null (ничего).
Бывает, что функция должна не только вернуть результат, но и сделать так, что бы он был виден и вне функции. Вот для этого и нужна передача параметров по ссылке, о которой я вам рассказал выше. Создадим функцию сложения двух чисел. Первый параметр мы умножим на двое, а во второй запишем произведение двух параметров.
stock Test(Var, Num) //Где Var - число которое возводим в степень, где Num - степень в которую возводим. { new var = Var; for(new i; i < Num; i++) { var = var*Var; } return var; }
Как видите, здесь мы использовали цикл, но можно обойтись и без него!
Так вот, Функция называется рекурсивной если вызывает саму себя.
Вот вам пример рекурсивной функции. Возведения числа в степень, но уже без цикла.
Как это работает? Мы вызываем функцию Test с параметром 2 и 5. Напомню, что в нашей функции первый параметр - число которое возводим в степень, второй параметр - степень. После вызова функции, она проверяет чему равна переменная num если она больше или равна (или равна, потому что отсчет в языках программирования идет с нуля), то функция умножает число на вызов самой себя, при этом num становится меньше на единицу. Зачем? Надо помнить, что необходимо предусматривать выход из рекурсии. Иначе она станет бесконечной и ваш скрипт (а вместе с ним и сервер) зависнет. В моем примере, выход из рекурсии - это if(num>=0) и num-1. Код выполняется только если num больше или равна нулю, а так как при каждом выполнении кода num уменьшается на один, бесконечной рекурсии не будет. Попробуйте убрать выход из рекурсии и проверьте что будет.
Stock и public: что это такое.
Функции объявляются по разному. Можно сделать так:
Code
stock Func_Name(var) { return 1; }
или так
Code
forward Func_Name(var); public Func_Name(var) { return 1; }
или даже
Code
Func_Name(var)
Первый случай чаще всего используют в инклудах. Если функция с префиксом stock нигде не используется (не вызывается), она не включается компилятором в скрипт. Именно по этому, если вы напишите ее с ошибкой и нигде не будете использовать, компилятор не выдаст ошибку. Но стоит вам ее вызвать, ошибки обнаружатся компилятором и он их вам выведет.
Второй случай с public используется в таймерах, в стандартных функциях и в CallRemoteFunction. Причем он требует обязательного объявления функции, путем forward Имя_Функции(аргументы).
Третий случай - аналог public, но он не требует объявления, но и не может использоваться в таймерах и в CallRemoteFunction. Итак:
Я вам рассказал что такое функции, как их создавать и вызывать
Почему не следует забывать про область видимости
Объяснил что такое передача параметров по ссылке и для чего это нужно
Что такое return и для чего он нужен
Что такое рекурсия и когда удобно ее применять
Кратко объяснил о типах функций
Ну вот и всё, что я хотел вам рассказать в данной теме. Я надеюсь что информация вам будет полезна. Копирайты и все такое:
Автор текста, темы, урока - _Dark_ (Если кто-то не в курсе, это я).
При перепечатывании статьи обратная ссылка на данную тему с указанием авторства [blink]обязательна[/blink].
От плюсика не откажусь Если есть вопросы - задавайте. Продолжение, как обычно, следует
Если баги возникают из ниоткуда - ты на правильном пути. (с)
Сообщение отредактировал _Dark_ - Среда, 03.08.2011, 13:23
stock IsPlayerRich(playerid) { if(GetPlayerMoney(playerid) > 1000000) return 1; // Если игрок имеет более 1 млн, то возвращаем return 1 или return true; else return 0; //или return false; }
Спор на форуме, все равно что олимпиада среди умственно отсталых: даже если ты победил, ты все равно гермофродит. Хочешь остаться при своем мнении - держи его при себе.
Morino_Reigan, можно и без скобок, но чтобы не запутаться в этих конструкциях я их не убираю
Спор на форуме, все равно что олимпиада среди умственно отсталых: даже если ты победил, ты все равно гермофродит. Хочешь остаться при своем мнении - держи его при себе.
if(IsPlayerRich(playerid)) // Если у игрока больше 1 млн. денег (функция вернет return 1) { SendClientMessageToAll(COLOR_LIGHTRED, "От нас ушел богатый игрок!"); } else SendClientMessageToAll(COLOR_LIGHTRED, "От нас ушел игрок!"); return 1;
Спор на форуме, все равно что олимпиада среди умственно отсталых: даже если ты победил, ты все равно гермофродит. Хочешь остаться при своем мнении - держи его при себе.
if(!strcmp(cmd,"/deletecar",true)) { if(GetPlayerState(playerid) != PLAYER_STATE_DRIVER) { SendClientMessage(playerid, COLOR_WHITE, "* Вы не в авто"); return 1; } new vehicleid = GetPlayerVehicleID(playerid); SendClientMessage(playerid, COLOR_WHITE, "Машина уничтожена"); DestroyVehicle(vehicleid); return 1; }
Спор на форуме, все равно что олимпиада среди умственно отсталых: даже если ты победил, ты все равно гермофродит. Хочешь остаться при своем мнении - держи его при себе.