"Язык, где код становится поэзией" - синтаксис Топаза стремится к максимальной выразительности при минимальном количестве кода. Освойте прекрасный синтаксис Топаза в этом полном руководстве. 🌟
🎯 Основная философия
"Писать меньше, выражать больше"
Даже сложную логику можно выразить кратко и читаемо.
Глобальный синтаксис, локальное выражение
- Ключевые слова: Унифицированы на английском (
function,let,match,case) - Идентификаторы: Свободное использование любого языка, русского, Unicode и даже эмодзи
Всё является выражением
Все конструкции типа if, match, for, try возвращают значения.
📝 Базовый синтаксис
Объявление переменных
// Неизменяемые переменные (по умолчанию)
let имя = "Алексей"
let возраст = 25
let активен = true
// Изменяемые переменные
mut let очки = 85
очки = 90 // Можно изменить
// Указание типа (опционально)
let расстояние: float = 3.14
let пользователи: Array<string> = ["Иван", "Мария"]
Присваивание объединения с null (??=)
Оператор‑заявление для инициализации, когда цель — None/null.
let mut name: Option<string> = None
name ??= Some("guest")
Определение функций
// Базовая функция
function приветствие(имя: string) -> string {
"Привет, {имя}!"
}
// Параметры по умолчанию
function вычислить(x: int, y: int = 10) -> int {
x + y
}
// Множественные возвращаемые значения
function получитьКоординаты() -> (int, int) {
(100, 200)
}
// Функции высшего порядка
function преобразовать(данные: Array<int>, функция: (int) -> int) -> Array<int> {
данные.map(функция)
}
Условные выражения
// if выражение (возвращает значение)
let сообщение = if возраст >= 20 {
"Вы взрослый"
} else if возраст >= 13 {
"Вы подросток"
} else {
"Вы ребёнок"
}
// В стиле тернарного оператора
let статус = if онлайн { "Подключён" } else { "Отключён" }
Сопоставление с образцом
// Базовое сопоставление
let результат = match значение {
case 1 => "Один"
case 2 => "Два"
case 3 => "Три"
case _ => "Другое"
}
// Сопоставление диапазонов
let оценка = match балл {
case 90..100 => "Отлично"
case 80..<90 => "Хорошо"
case 70..<80 => "Удовлетворительно"
case _ => "Неудовлетворительно"
}
// Структурное сопоставление
let скидка = match клиент {
case { уровень: "VIP", сумма } if сумма > 1000000 => 0.3
case { уровень: "VIP" } => 0.2
case { датаРегистрации } if сегодня - датаРегистрации > 365.дней => 0.1
case _ => 0.0
}
#### Списковые паттерны
```rust
match xs {
case [head, ..tail] => useHead(head, tail)
case [..init, last] => useLast(init, last)
case [a, .., z] => useEnds(a, z)
case [x, y, ..rest] if rest.length > 0 => handle(x, y, rest)
}
Сквозной пример (guard + вложенный списковый паттерн):
let описание = match числа {
case [] => "пусто"
case [один] => "один"
case [первый, .., последний] if первый < последний => "восходящий край"
case [первый, ..середина, последний] => "края {первый}..{последний}, середина={середина.length}"
}
## 🌊 Конвейерные операции
### Базовый конвейер
```rust
// Данные текут как поэзия
let результат = исходныеДанные
|> нормализовать()
|> фильтровать(x => x > 0)
|> преобразовать(x => x * 2)
|> сортировать()
Смешивание с цепочкой методов
let обработаннаяСтрока = "привет мир"
.split(" ")
|> каждому(слово => слово.заглавная())
.join(" ")
|> добавить("!", _)
// Результат: "Привет Мир!"
Сахар для конвейера
v4Короткие формы справа от |>:
value
|> .length // сахар свойства: (x => x.length)
|> replace("foo", _, "bar") // сахар вызова: (x => replace("foo", x, "bar"))
// Несколько `_` связываются слева-направо в ближайшем вызове
value |> format("id=", _, ":", _)
🧠 Система типов
Вывод типов
// Типы автоматически выводятся
let число = 42 // int
let текст = "привет" // string
let массив = [1, 2, 3, 4] // Array<int>
let объект = { // { имя: string, возраст: int }
имя: "Алексей",
возраст: 25
}
Литеральные типы
// Ограничение типов точными значениями
type СветофорЦвет = "красный" | "жёлтый" | "зелёный"
type БросокКубика = 1 | 2 | 3 | 4 | 5 | 6
type КодСостояния = 200 | 404 | 500
function обработатьСигнал(цвет: СветофорЦвет) {
match цвет {
case "красный" => стоп()
case "жёлтый" => осторожно()
case "зелёный" => ехать()
// Компилятор проверяет, что все случаи обработаны!
}
}
Объединённые типы
type ПользовательскийВвод = string | int | null
function обработать(ввод: ПользовательскийВвод) -> string {
match ввод {
case с: string => "Строка: {с}"
case н: int => "Число: {н}"
case null => "Нет ввода"
}
}
🔁 Циклы
Циклы for (выражения)
// Итерация по диапазону
for i in 1..10 {
print("Число: {i}")
}
// Итерация по массиву
for элемент in ["яблоко", "банан", "вишня"] {
print("Фрукт: {элемент}")
}
// С индексом
for (индекс, значение) in данные.enumerate() {
print("{индекс}: {значение}")
}
// for тоже возвращает значения!
let квадраты = for x in 1..5 { x * x } // [1, 4, 9, 16]
Шаг диапазона с by
v4
// Шаг вперёд
for i in 0..10 by 2 { print(i) } // 0,2,4,6,8,10
// Шаг назад (отрицательный шаг)
for i in 10..0 by -3 { print(i) } // 10,7,4,1
// Шаг по датам/времени (библиотечные длительности)
for day in startDate..endDate by 1.day { расписание.добавить(day) }
Циклы while
mut let счётчик = 0
while счётчик < 10 {
print("Счётчик: {счётчик}")
счётчик = счётчик + 1
}
📚 Коллекции
Массивы
// Базовые массивы
let числа = [1, 2, 3, 4, 5]
let фрукты = ["яблоко", "банан", "вишня"]
// Методы массивов
let большие = числа.filter(x => x > 2) // [3, 4, 5]
let квадраты = числа.map(x => x * x) // [1, 4, 9, 16, 25]
let сумма = числа.reduce(0, +) // 15
Принадлежность (in)
// Массивы/Списки/Множества
let ok1 = 3 in [1, 2, 3]
let ok2 = "a" in Set.of("a", "b")
// Ключи map
let hasId = "id" in userMap.keys
// Диапазоны
let inside = 5 in 1..10
let outside = 10 in 1..<10
Объекты/Структуры
// Литерал объекта
let пользователь = {
имя: "Алексей",
возраст: 25,
email: "aleksey@example.com"
}
// Определение структуры
struct Пользователь {
имя: string,
возраст: int,
email: string
}
// Экземпляр структуры
let новыйПользователь = Пользователь {
имя: "Мария",
возраст: 30,
email: "maria@example.com"
}
Литерал обновления записи
v4Немутируемое обновление: мелкое копирование записи с изменением выбранных полей.
let user = { name: "Alice", age: 20, city: "Seoul" }
let updated = user{ age: user.age + 1, city: "Busan" }
// { name: "Alice", age: 21, city: "Busan" }
🎭 Строковые шаблоны
Базовая интерполяция
let имя = "Алексей"
let возраст = 25
let приветствие = "Привет, {имя}! Вам {возраст} лет."
Тегированные шаблоны
v4Стандартизированные теги с сохранением метаданных и безопасностью:
let путь = p"/home/{user}/docs/{fileName}" // нормализация пути
let шаблон = r"^[a-z0-9_]+$" // регулярные выражения с лёгкими экранированиями
let команда = sh"grep {шаблон} {файл}" // безопасный shell‑шаблон (политики выполнения)
// SQL: параметры всегда привязываются (никакой прямой вставки строк)
let запрос = sql"SELECT * FROM users WHERE age > {возраст} AND city = {город}"
⚡ Асинхронная обработка
Автоматическая асинхронность
// I/O автоматически асинхронный, но пишется как синхронный!
function получитьИнфоПользователя(id: int) -> Пользователь {
let основнаяИнфо = API.получитьПользователя(id) // авто async обработка
let профиль = API.получитьПрофиль(id) // авто async обработка
Пользователь {
основнаяИнфо: основнаяИнфо,
профиль: профиль
}
}
Параллельное выполнение
// Запуск нескольких задач параллельно
let результаты = concurrent {
погода: ПогодаAPI.текущая("Москва"),
курс: ВалютаAPI.курсДоллара(),
новости: НовостиAPI.заголовки(5)
}
🛡️ Обработка ошибок
Тип Result
function безопасноеДеление(a: int, b: int) -> Result<int, string> {
if b == 0 {
Err("Нельзя делить на ноль")
} else {
Ok(a / b)
}
}
// Просто с оператором ?
function сложноеВычисление(x: int) -> Result<int, string> {
let результат1 = безопасноеДеление(x, 2)?
let результат2 = безопасноеДеление(результат1, 3)?
Ok(результат2 * 10)
}
Выражение try
let конфигурация = try {
прочитатьФайл("config.json")?
} else {
// Вернуть значение по умолчанию
{ тема: "тёмная", язык: "русский" }
}
🎨 Продвинутые возможности
Частичное применение
let добавить10 = добавить(10, _)
let результат = [1, 2, 3].map(добавить10) // [11, 12, 13]
Опциональная безопасная цепочка (?.)
Используйте ?. только когда слева Option<T> или объединение с null (например, T | null). Оператор сводится к Option.map/flatMap и выполняется слева направо с коротким замыканием.
let user: Option<{ name: string, profile: Option<{ city: string }> }> =
Some({ name: "Ann", profile: Some({ city: "Seoul" }) })
let nameOpt = user?.name
let cityOpt = user?.profile?.city
// С комбинированием с ?? для значений по умолчанию
let city = user?.profile?.city ?? "Unknown"
// Это не общий объектный чейнинг — для обычных значений используйте `.`
let plain = { name: "Jo" }
let ok = plain.name
Эквивалентность с map/flatMap:
// user?.profile?.city
let viaFns = user
|> Option.flatMap(_, u => u.profile)
|> Option.map(_, p => p.city)
Макросы
// Макрос повторного выполнения
macro повторитьВыполнение(раз: int) {
for i in 1..раз {
print("Выполнение {i}/{раз}")
yield // Выполнить пользовательский код
}
}
повторитьВыполнение(3) {
важнаяЗадача()
}
🔧 Практические примеры
Вызов веб-API
let данныеПользователя = fetch("https://api.example.com/users/1")
|> json()
|> (данные => {
имя: данные.name,
email: данные.email,
датаРегистрации: Date.parse(данные.created_at)
})
Конвейер обработки данных
let результатАнализа = CSV.прочитать("продажи.csv")
|> фильтр(строка => строка.выручка > 1000000)
|> группировать(строка => строка.регион)
|> агрегировать(группа => {
регион: группа.ключ,
общаяВыручка: группа.значения.сумма(строка => строка.выручка),
средняяВыручка: группа.значения.среднее(строка => строка.выручка)
})
|> сортировать(поУбыванию: строка => строка.общаяВыручка)
🎯 Следующие шаги
Теперь вы освоили базовый синтаксис Топаза! Что изучать дальше:
- Типы данных - Глубокое погружение в систему типов
- Функции и замыкания - Освоение функционального программирования
- Обработка ошибок - Написание безопасного, надёжного кода
Продолжайте своё путешествие, где программирование становится поэзией с Топазом! ✨