Функции и передача параметров по ссылке var
Урок учит писать функции, возвращающие значение, и объясняет разницу между передачей параметров по значению и по ссылке var.
Функция — это подпрограмма, которая вычисляет и возвращает значение, которое можно использовать в выражениях.
Чем функция отличается от процедуры
Процедура выполняет действие (печатает, рисует, меняет данные). А функция вычисляет и возвращает результат — число, строку, логическое значение, — который можно подставить в выражение, присвоить переменной или вывести. Вы уже пользовались встроенными функциями: sqrt(9) возвращает 3, length(s) возвращает длину. Теперь научимся писать свои.
Простое правило: если подпрограмма должна что-то вернуть для дальнейших вычислений — это функция. Если она просто что-то делает — это процедура.
Объявление функции
Функцию описывают словом function, и в её заголовке после параметров через двоеточие указывают тип возвращаемого значения. Результат внутри функции присваивают специальному имени Result (или, в классическом стиле, имени самой функции):
function Kvadrat(x: integer): integer; // вернёт integer
begin
Result := x * x; // присваиваем результат
end;
begin
writeln(Kvadrat(5)); // 25
writeln(Kvadrat(3) + Kvadrat(4)); // 9 + 16 = 25
end.
Заголовок function Kvadrat(x: integer): integer читается так: «функция Kvadrat принимает целое x и возвращает целое». Строка Result := x * x задаёт, что вернуть. Главное преимущество видно во второй строке: вызов функции можно подставлять прямо в выражение, складывать, сравнивать — как обычное значение. В классическом Паскале вместо Result пишут имя функции: Kvadrat := x * x; оба варианта работают в PascalABC.NET. Запустите аналог на Python (там результат возвращают через return):
def kvadrat(x):
return x * x
print(kvadrat(5))
print(kvadrat(3) + kvadrat(4))
Вывод:
25 25
Функция с логическим результатом
Очень полезны функции, возвращающие boolean — они отвечают на вопрос «да или нет» и красиво читаются в условиях:
def chetnoe(n):
return n % 2 == 0
for x in [4, 7, 10]:
if chetnoe(x):
print(x, '- чётное')
else:
print(x, '- нечётное')
Вывод:
4 - чётное 7 - нечётное 10 - чётное
На Паскале это была бы function Chetnoe(n: integer): boolean; begin Result := n mod 2 = 0; end;, а в условии — if Chetnoe(x) then .... Такой код читается почти как человеческий язык.
Параметры по значению: копия данных
До сих пор все параметры мы передавали по значению: функция получает копию данных. Что бы она ни делала с параметром внутри, на исходную переменную это не влияет — она работает с копией. Это безопасно и используется по умолчанию:
def isportit(x):
x = 999 # меняем копию
print('Внутри:', x)
a = 10
isportit(a)
print('Снаружи a:', a) # a не изменилась
Вывод:
Внутри: 999 Снаружи a: 10
Видите? Внутри параметр стал 999, но снаружи a осталась 10 — менялась копия. В большинстве случаев это именно то, что нужно.
Параметры по ссылке: ключевое слово var
Но иногда нужно, чтобы подпрограмма изменила исходную переменную. Например, процедура обмена должна реально поменять значения у вызывающей стороны. Для этого параметр объявляют с ключевым словом var — тогда он передаётся по ссылке: подпрограмма работает не с копией, а с самой исходной переменной.
procedure Obmen(var a, b: integer); // var — по ссылке!
var
temp: integer;
begin
temp := a;
a := b;
b := temp;
end;
var
x, y: integer;
begin
x := 1;
y := 2;
Obmen(x, y); // меняет сами x и y
writeln('x = ', x, ', y = ', y); // x = 2, y = 1
end.
Без var процедура поменяла бы местами лишь свои копии, и снаружи x и y остались бы прежними. Слово var перед параметром — это «работай с оригиналом, а не с копией». Так же через var возвращают несколько результатов сразу (функция возвращает только одно значение, а процедура с несколькими var-параметрами — сколько угодно). Различие наглядно:
| Признак | По значению | По ссылке (var) |
| Что получает подпрограмма | копию данных | саму переменную |
| Изменения видны снаружи? | нет | да |
| Когда использовать | обычные вычисления | когда нужно изменить переменную |
Попробуй сам
Напишите функцию Maximum(a, b), которая возвращает большее из двух чисел, и используйте её, чтобы найти максимум из трёх: Maximum(Maximum(x, y), z). Проверьте на Python:
def maximum(a, b):
if a > b:
return a
else:
return b
x, y, z = 7, 3, 9
print('Максимум из трёх:', maximum(maximum(x, y), z))
Вывод:
Максимум из трёх: 9
Частые ошибки
- Забыли задать Result. Если внутри функции не присвоить
Result(или имя функции), она вернёт мусор. Каждая ветка должна задавать результат. - Не указали тип возврата. В заголовке функции после параметров обязателен
: тип, иначе это будет процедура. - Ждут изменения переменной без var. Без
varподпрограмма меняет лишь копию; чтобы изменить оригинал, параметр объявляют сvar. - Передают выражение в var-параметр. По ссылке (
var) можно передавать только переменную, а не выражение вродеObmen(x + 1, y)— оригинала у выражения нет.
Итоги
- Функция вычисляет и возвращает значение; в заголовке указывают тип возврата, результат задают через
Resultили имя функции. - Вызов функции можно подставлять в выражения, как обычное значение; функции с
booleanудобны в условиях. - По умолчанию параметры передаются по значению — подпрограмма работает с копией, оригинал не меняется.
- Параметр с ключевым словом
varпередаётся по ссылке: изменения видны снаружи. - Через
var-параметры процедура может «вернуть» сразу несколько значений.