Функции являются гражданами первого класса в Топазе. Вы можете сохранять их в переменных, передавать в качестве параметров другим функциям и возвращать из функций. ��
🔧 Базовое объявление функций
Стандартное объявление функции
// Базовая структура функции
function приветствовать(имя: string) -> string {
return "Привет, {имя}!"
}
// Функция без параметров
function получитьТекущееВремя() -> string {
return "20 декабря 2024"
}
// Функция без возвращаемого значения (void)
function вывестиСообщение(сообщение: string) {
print("Лог: {сообщение}")
}
// Примеры использования
let приветствие = приветствовать("Топаз Разработчик")
print(приветствие) // "Привет, Топаз Разработчик!"
Параметры и значения по умолчанию
// Значения параметров по умолчанию
function вычислить(a: int, b: int = 10, операция: string = "сложение") -> int {
match операция {
case "сложение" => return a + b
case "вычитание" => return a - b
case "умножение" => return a * b
case _ => return 0
}
}
// Различные способы вызова
let результат1 = вычислить(5) // 5 + 10 = 15
let результат2 = вычислить(5, 3) // 5 + 3 = 8
let результат3 = вычислить(5, 3, "умножение") // 5 * 3 = 15
// Именованные параметры
let результат4 = вычислить(a: 8, операция: "вычитание", b: 3) // 8 - 3 = 5
Вариативные параметры
// Вариативные параметры (...rest)
function сумма(числа: ...int) -> int {
let mut итого = 0
for число in числа {
итого += число
}
return итого
}
let итого1 = сумма(1, 2, 3, 4, 5) // 15
let итого2 = сумма(10, 20) // 30
// Комбинирование массива с дополнительными параметрами
function вычислитьСтатистику(метка: string, значения: ...float) -> string {
let количество = значения.length()
let среднее = значения.sum() / количество
return "{метка}: количество={количество}, среднее={среднее}"
}
print(вычислитьСтатистику("Результаты тестов", 85.5, 92.0, 78.5, 89.0))
➡️ Стрелочные функции
Базовые стрелочные функции
// Простая стрелочная функция
let квадрат = (x: int) => x * x
let приветствие = (имя: string) => "Привет, {имя}!"
// Стрелочная функция без параметров
let случайноеЧисло = () => Math.random() * 100
// Сложная стрелочная функция
let информацияПользователя = (имя: string, возраст: int) => {
let статус = if возраст >= 18 { "взрослый" } else { "несовершеннолетний" }
return {
имя: имя,
возраст: возраст,
статус: статус
}
}
// Примеры использования
print(квадрат(5)) // 25
print(приветствие("ТопазДев")) // "Привет, ТопазДев!"
let информация = информацияПользователя("Иван", 25)
print(информация) // { имя: "Иван", возраст: 25, статус: "взрослый" }
Методы массивов со стрелочными функциями
let числа = [1, 2, 3, 4, 5]
// map преобразование
let квадраты = числа.map(x => x * x)
print(квадраты) // [1, 4, 9, 16, 25]
// filter фильтрация
let четные = числа.filter(x => x % 2 == 0)
print(четные) // [2, 4]
// reduce сведение
let итого = числа.reduce((аккум, текущий) => аккум + текущий, 0)
print(итого) // 15
// Сложное связывание
let результат = числа
.filter(x => x > 2)
.map(x => x * 3)
.reduce((a, b) => a + b, 0)
print(результат) // (3 + 4 + 5) * 3 = 36
🎯 Функции высшего порядка
Функции как параметры
// Определение функции высшего порядка
function применитьОперацию(массив: [int], операция: function(int) -> int) -> [int] {
let результат = []
for элемент in массив {
результат.push(операция(элемент))
}
return результат
}
// Передача функций как параметров
let числа = [1, 2, 3, 4]
let результатКвадратов = применитьОперацию(числа, x => x * x)
let результатУдвоения = применитьОперацию(числа, x => x * 2)
print(результатКвадратов) // [1, 4, 9, 16]
print(результатУдвоения) // [2, 4, 6, 8]
// Функция условной обработки
function условнаяОбработка(значение: int, условие: function(int) -> bool, обработчик: function(int) -> int) -> int {
if условие(значение) {
return обработчик(значение)
}
return значение
}
let результат = условнаяОбработка(15, x => x > 10, x => x * 2)
print(результат) // 30 (поскольку 15 > 10, то 15 * 2)
Возврат функций
// Фабрика функций
function создатьУмножитель(множитель: int) -> function(int) -> int {
return function(x: int) -> int {
return x * множитель
}
}
let удвоитель = создатьУмножитель(2)
let утроитель = создатьУмножитель(3)
print(удвоитель(5)) // 10
print(утроитель(4)) // 12
// Настраиваемая функция валидации
function создатьВалидаторДиапазона(мин: int, макс: int) -> function(int) -> bool {
return function(значение: int) -> bool {
return значение >= мин && значение <= макс
}
}
let валидаторВозрастаВзрослых = создатьВалидаторДиапазона(18, 65)
let валидаторВозрастаСтудентов = создатьВалидаторДиапазона(5, 18)
print(валидаторВозрастаВзрослых(25)) // true
print(валидаторВозрастаСтудентов(16)) // true
print(валидаторВозрастаСтудентов(25)) // false
🔒 Замыкания
Базовые замыкания
function создатьСчетчик(начальноеЗначение: int) -> function() -> int {
let mut счет = начальноеЗначение // Захватывается замыканием
return function() -> int {
счет += 1 // Доступ к внешней переменной
return счет
}
}
let счетчик1 = создатьСчетчик(0)
let счетчик2 = создатьСчетчик(100)
print(счетчик1()) // 1
print(счетчик1()) // 2
print(счетчик2()) // 101
print(счетчик1()) // 3
Сложные паттерны замыканий
// Замыкание с состоянием
function создатьСчет(начальныйБаланс: float) -> { пополнить: function(float) -> float, снять: function(float) -> float, проверитьБаланс: function() -> float } {
let mut баланс = начальныйБаланс
return {
пополнить: function(сумма: float) -> float {
баланс += сумма
return баланс
},
снять: function(сумма: float) -> float {
if сумма <= баланс {
баланс -= сумма
}
return баланс
},
проверитьБаланс: function() -> float {
return баланс
}
}
}
let мойСчет = создатьСчет(1000.0)
print(мойСчет.пополнить(500.0)) // 1500.0
print(мойСчет.снять(200.0)) // 1300.0
print(мойСчет.проверитьБаланс()) // 1300.0
// Замыкание, захватывающее окружение
function создатьМенеджерКонфигурации(базоваяКонфигурация: { [string]: any }) -> function(string, any) -> any {
let mut текущаяКонфигурация = базоваяКонфигурация.copy()
return function(ключ: string, значение: any = null) -> any {
if значение != null {
текущаяКонфигурация[ключ] = значение
}
return текущаяКонфигурация[ключ]
}
}
let конфигурацияПриложения = создатьМенеджерКонфигурации({
тема: "темная",
язык: "Русский",
уведомления: true
})
print(конфигурацияПриложения("тема")) // "темная"
конфигурацияПриложения("тема", "светлая")
print(конфигурацияПриложения("тема")) // "светлая"
🔄 Рекурсивные функции
Базовая рекурсия
// Вычисление факториала
function факториал(n: int) -> int {
if n <= 1 {
return 1
}
return n * факториал(n - 1)
}
print(факториал(5)) // 120
// Последовательность Фибоначчи
function фибоначчи(n: int) -> int {
if n <= 1 {
return n
}
return фибоначчи(n - 1) + фибоначчи(n - 2)
}
print(фибоначчи(8)) // 21
// Сумма массива (рекурсивно)
function суммаМассива(массив: [int]) -> int {
if массив.length() == 0 {
return 0
}
if массив.length() == 1 {
return массив[0]
}
return массив[0] + суммаМассива(массив.slice(1))
}
print(суммаМассива([1, 2, 3, 4, 5])) // 15
Оптимизация хвостовой рекурсии
// Хвостово-рекурсивный факториал
function хвостовойФакториал(n: int, аккумулятор: int = 1) -> int {
if n <= 1 {
return аккумулятор
}
return хвостовойФакториал(n - 1, аккумулятор * n) // Хвостовой вызов
}
// Хвостово-рекурсивный Фибоначчи
function хвостовойФибоначчи(n: int, a: int = 0, b: int = 1) -> int {
if n == 0 {
return a
}
return хвостовойФибоначчи(n - 1, b, a + b) // Хвостовой вызов
}
print(хвостовойФакториал(10)) // 3628800
print(хвостовойФибоначчи(10)) // 55
⚡ Паттерны функционального программирования
Каррирование
// Каррированная функция
function сложить(a: int) -> function(int) -> int {
return function(b: int) -> int {
return a + b
}
}
let прибавитьПять = сложить(5)
print(прибавитьПять(3)) // 8
// Многопараметровое каррирование
function умножитьИСложить(множитель: float) -> function(float) -> function(float) -> float {
return function(слагаемое: float) -> function(float) -> float {
return function(значение: float) -> float {
return значение * множитель + слагаемое
}
}
}
let удвоитьИПрибавитьДесять = умножитьИСложить(2.0)(10.0)
print(удвоитьИПрибавитьДесять(5.0)) // 20.0 (5 * 2 + 10)
Композиция функций
// Утилита композиции функций
function составить<T, U, V>(f: function(U) -> V, g: function(T) -> U) -> function(T) -> V {
return function(x: T) -> V {
return f(g(x))
}
}
let квадрат = (x: int) => x * x
let удвоить = (x: int) => x * 2
let вСтроку = (x: int) => x.toString()
// Составление функций
let квадратЗатемУдвоить = составить(удвоить, квадрат)
let квадратЗатемУдвоитьЗатемСтрока = составить(вСтроку, квадратЗатемУдвоить)
print(квадратЗатемУдвоить(3)) // 18 (3² * 2)
print(квадратЗатемУдвоитьЗатемСтрока(4)) // "32" (4² * 2 → строка)
Мемоизация
// Декоратор мемоизации
function мемоизировать<T, R>(функция: function(T) -> R) -> function(T) -> R {
let mut кеш = {}
return function(вход: T) -> R {
let ключ = вход.toString()
if ключ in кеш.keys {
return кеш[ключ]
}
let результат = функция(вход)
кеш[ключ] = результат
return результат
}
}
// Оптимизация медленного Фибоначчи с мемоизацией
let мемоФибоначчи = мемоизировать(function(n: int) -> int {
if n <= 1 return n
return мемоФибоначчи(n - 1) + мемоФибоначчи(n - 2)
})
// Теперь большие числа вычисляются быстро
print(мемоФибоначчи(40)) // Вычисляется быстро
🛡️ Оптимизация функций и лучшие практики
1. Использование чистых функций
// Хорошо: Чистая функция
function вычислитьНалог(доход: float, налоговаяСтавка: float) -> float {
return доход * налоговаяСтавка
}
// Избегайте: Функция с побочными эффектами
let mut глобальныйСчетчик = 0
function плохаяФункция(значение: int) -> int {
глобальныйСчетчик += 1 // Побочный эффект!
return значение * 2
}
// Хорошая альтернатива: Возврат состояния
function хорошаяФункция(значение: int, текущийСчетчик: int) -> { результат: int, новыйСчетчик: int } {
return {
результат: значение * 2,
новыйСчетчик: текущийСчетчик + 1
}
}
2. Именование функций и структурирование
// Четкие имена функций
function валидироватьEmailПользователя(email: string) -> bool {
return email.contains("@") && email.contains(".")
}
function вычислитьОбщуюСуммуЗаказа(элементыЗаказа: [{ цена: float, количество: int }]) -> float {
return элементыЗаказа
.map(элемент => элемент.цена * элемент.количество)
.reduce((общее, сумма) => общее + сумма, 0.0)
}
// Принцип единственной ответственности
function разобратьДанныеПользователя(исходныеДанные: string) -> { имя: string, возраст: int } {
// Отвечает только за разбор
let части = исходныеДанные.split(",")
return {
имя: части[0].trim(),
возраст: parseInt(части[1].trim())
}
}
function валидироватьДанныеПользователя(пользователь: { имя: string, возраст: int }) -> bool {
// Отвечает только за валидацию
return пользователь.имя.length() > 0 && пользователь.возраст > 0
}
3. Обработка ошибок
// Безопасная функция с типом Result
function безопасноеДеление(числитель: float, знаменатель: float) -> Result<float, string> {
if знаменатель == 0.0 {
return Err("Нельзя делить на ноль")
}
return Ok(числитель / знаменатель)
}
// Использование
match безопасноеДеление(10.0, 2.0) {
case Ok(результат) => print("Результат: {результат}")
case Err(ошибка) => print("Ошибка: {ошибка}")
}
Функции и замыкания являются основными возможностями Топаз. Их эффективное использование позволяет писать переиспользуемый и тестируемый код! 🎯