1.6. Функции#
Функция в Julia один из основных инструментов повторного использования кода.
Больше информации в мануале [url].
TL;DR
Длинная и компактная формы синтаксиса;
Анонимные функции;
Функция – first-class объект;
Принцип передачи аргументов – pass by sharing;
Операторы определены через функции;
Аргументы и возвращаемое значение определены через кортежи;
Аргументы бывают позиционными, по ключу, могут иметь значение по умолчанию.
Основной синтаксис для функций в Julia
julia> function f(x, y)
return sqrt(x^2 + y^2)
end
f (generic function with 1 method)
Строго говоря, команда return
необязательна: функция в Julia возвращает результат последнего выражения, однако, мы будем придерживаться .
В теле функции может находиться несколько команд return
, в этом случае при вызове сработает только одна из них.
Если необходимо, чтобы функция ничего не возвращала, тогда используется return nothing
.
Тип Nothing
имеет лишь одно значение nothing
, представляющее в Julia отутствие значения.
Зачастую пригождается более краткий синтаксис создания функции (assignment form)
julia> f(x, y) = sqrt(x^2 + y^2)
f (generic function with 1 method)
В этом случае справа от =
может находиться составное выражение (compound expression) begin-end
.
julia> g(x, y) = begin # или g(x, y) = begin z = f(x, y); return 2*z end
z = f(x, y)
return 2*z
end
g (generic function with 1 method)
О составных выражениях
Блок begin-end
позволяет объединять несколько выражений в одно, составное выражение (compound expression). Результат выражения это результат последнего вычисления в выражении.
julia> z = begin
x = 1
y = 2
x + y
end
3
julia> x, y
(1, 2)
Как видно из примера, begin-end
исполняется во внешнем пространстве имён. Его двойник блок let-end
создаёт собственное пространство имён. Внутри let-end
можно пользоваться именами извне, но если происходит присвоение, то имя создаётся внутри видимости let-end
.
julia> x, y = 1, 2
(1, 2)
julia> let
x = 10
y = 20
x + y
end
30
julia> x, y
(1, 2)
С помощью ;
можно поместить несколько выражений на одной строке, что часто используется для коротких составных выражений или депривации вывода в REPL.
julia> z = (x = 1; y = 2; x + y)
3
julia> z = begin x = 1; y = 2; x + y end
3
Предназначение ;
аналогично его предназначению в C-подобных языках, но в Julia не требуется ставить ;
после каждой инструкции.
Синтаксис вызова интуитивен
julia> f(3, 4)
5.0
julia> g(3, 4)
10.0
В Julia аргументы передаются по принципу pass-by-sharing. Т.е. аргументы функции внутри тела ведут себя как новые переменные. Однако, у изменяемых mutable аргументов (например, массив), можно поменять значения, и они будут видны извне. По соглашению, если функция меняет свой аргумент, то в её имя добавляется !
в конце, например, map!(f, A, B)
, push!(A, x)
(исключение составляют функции, работающие с вводом-выводом print
, write
,..).
Функции являются first-class объектами. Ими можно «распоряжаться», как переменными: присваивать их другим переменным, передавать как аргумент…
julia> φ = f;
julia> φ(3, 4)
5.0
Важно, что операторы (+-*/
, in
, ==
, &&
…) в Julia также являются функциями, просто имя такой функции это символ(ы) оператора
julia> +(1, 2, 3) == 1 + 2 + 3
true
Языковые конструкции, вроде доступа к элементу массива (A[i]
) или полю структуры (S.x
) являются операторами c функциональными аналогами.
Можно создавать анонимные функции (anonymous functions). Они обычно передаются в другие функции, например, в сортировку или фильтрацию массивов.
julia> x -> 2x # короткий синтаксис
#1 (generic function with 1 method)
julia> f4 = x -> 2x # анонимная функция x -> 2x присвоена переменной f4
#3 (generic function with 1 method)
julia> f4(8)
16
julia> function (x) # длинный синтаксис
return 3x
end
#5 (generic function with 1 method)
julia> map(x -> 3x, 1:4) # пример применения
4-element Vector{Int64}: # map здесь создает массив
3 # из утроенных значений
6 # арифм. прогрессии от 1 до 4
9
12
Аргументы функции в Julia представлены кортежем Tuple
.
Кортеж это неизменная коллекция, которая может содержать данные разных типов.
julia> tup = (3, 4)
(3, 4)
julia> tup[1]
3
julia> (3,) # tuple из одного значения
(3,)
Julia позволяет создавать функции с переменным числом аргументов. В таком случае один из аргументов хранит все поданные значения в виде кортежа.
julia> f(x, y...) = @show x y typeof(y)
f (generic function with 2 methods)
julia> f(1, 2, "a")
x = 1
y = (2, "a")
typeof(y) = Tuple{Int64, String}
Tuple{Int64, String}
Функция может возвращать несколько значений. В таком случае возвращается кортеж. Так, функция превращает один кортеж значений (аргументы) в другой (возвращаемое значение).
julia> function addmul(x, y)
return x + y, x * y # или return (x + y, x * y)
end
addmul (generic function with 1 method)
julia> a, b = addmul(3, 4)
(7, 12)
julia> a
7
julia> b
12
Также существует именованный кортеж NamedTuple
.
В отличие от обычного кортежа, доступ к элементам кортежа можно получить по имени поля.
julia> ntup = (a=10, b="xyz")
(a = 10, b = "xyz")
julia> typeof(ntup)
NamedTuple{(:a, :b), Tuple{Int64, String}}
julia> ntup.a, ntup.b
(10, "xyz")
julia> ntup[1], ntup[2]
(10, "xyz")
julia> ntup[:a], ntup[:b]
(10, "xyz")
На основе NamedTuple
создаются функции, принимающие аргументы по ключу.
Чтобы отделить позиционные аргументы от аргументов по ключу используется точка с запятой ;
.
При вызове функции ;
можно опускать, но мы не рекомендуем этого делать.
julia> f(; x, y) = x + y
f (generic function with 3 methods)
julia> f(; x=1, y=10)
11
Аргументам (позиционным и по ключу) можно присваивать значения по умолчанию.
julia> f(x; factor=10) = factor * x
f (generic function with 4 methods)
julia> f(15)
150
julia> f(15; factor=2)
30
1.6.1. Упражнения#
function f(x, y = 2, z...; a = 10, b, c...)
answer = ...
return answer
end
Ответьте на вопросы про каждый аргумент функции выше
Позиционный или по ключу
Обязательный при вызове или нет
Имеет ли значение по умолчанию
Является ли коллекцией аргументов при вызове
Позиционный; обязательный.
Позиционный; необязательный, поскольку имеет значение по умолчанию.
Содержит все позиционные аргументы, за исключением x
и y
; необязательный.
По ключу; необязательный, поскольку имеет значение по умолчанию.
По ключу; обязательный.
Содержит все аргументы по ключу, за исключением a
и b
; необязательный.