Шаг 2. Функции
Зачем#
Функция — основная единица повторного использования. В OxL сигнатура функции — это её контракт: типы параметров, тип результата и (о чём шаг 8) эффекты описаны в одном месте. Поэтому читать код можно, не заглядывая в тела функций.
Тело функции — выражение: последнее выражение блока и есть результат, return нужен только для раннего выхода. if и match
тоже выражения, поэтому тернарного оператора в языке нет — он не нужен.
Пример#
fn square(x: i32) -> i32 pure => x * x // pure — без побочных эффектов
fn greet(name: str, greeting: str = "Hello", loud: bool = false) -> str pure {
let text = "{greeting}, {name}"
if loud { text.upper() } else { text } // if — выражение; последнее выражение блока — результат
}
// вариадический параметр: внутри функции xs — срез
fn sumAll(...xs: i32) -> i32 pure {
var total = 0
for x in xs { total += x }
total
}
fn apply(f: fn(i32) -> i32, x: i32) -> i32 pure => f(x)
fn main() io {
print("{square(7)}")
print(greet("Ann"))
print(greet("Bob", loud: true)) // именованный аргумент
print("{sumAll(1, 2, 3, 4)}")
let k = 10
let addK = (x: i32) => x + k // замыкание захватывает k
print("{apply(addK, 5)} {apply(square, 6)}")
}Вывод
49 Hello, Ann HELLO, BOB 10 15 36
Разбор#
fn square(x: i32) -> i32 pure => x * x— короткая форма=> выражение. Словоpureозначает «без побочных эффектов»: такую функцию можно вызвать откуда угодно.greeting: str = "Hello"— значение по умолчанию вычисляется при каждом вызове, где аргумент опущен. Необязательные параметры удобно передавать по имени:greet("Bob", loud: true). Сначала идут позиционные аргументы, потом именованные....xs: i32— вариативный параметр; внутри функции это срез[i32], по которому можно пройти цикломfor.(x: i32) => x + k— лямбда. Она захватываетkиз окружающего кода. Функцию можно передать как значение: параметрf: fn(i32) -> i32принимает и лямбду, и обычную функциюsquare.- Сигнатуры функций с
pub/pub(api)пишутся полностью; у приватных функций тип результата может быть выведен из=> выражения.
Типичная ошибка: неверное число аргументов#
fn add(a: i32, b: i32) -> i32 => a + b
fn main() {
let s = add(1)
}error
arg-count
Компилятор называет функцию и сообщает, сколько аргументов ожидалось: arg-count. Если параметр
должен быть необязательным, дайте ему значение по умолчанию. Имя несуществующего именованного параметра даёт
named-arg.
Что запомнить#
- Результат — последнее выражение;
return— для раннего выхода. - Значения по умолчанию + именованные аргументы заменяют перегрузку функций.
- Лямбды и функции взаимозаменяемы там, где ожидается
fn(…) -> ….
Дальше: данные: data и enum.