Topaz намеренно держит public canonical поверхность функций небольшой. Имена ниже можно использовать в public-примерах без изобретения большой стандартной библиотеки. Будущая спецификация стандартной библиотеки может уточнить эту поверхность, но canonical-документация остаётся в рамках форм ниже.
Вывод и преобразование
print принимает только string. Нестроковые значения выводятся через интерполяцию. toInt(text: string) возвращает Option<int> и никогда не падает молча: обрабатывайте случай None явно.
print("Hello, Topaz!")
// toInt возвращает Option<int>
let ответ = match toInt("42") {
case Some(значение) => значение
case None => 0
}
print("Разобранный ответ: {ответ}")function разобратьПорт(текст: string) -> Result<int, string> {
if текст == "" {
return Err("Порт обязателен")
}
match toInt(текст) {
case Some(порт) => Ok(порт)
case None => Err("Порт должен быть целым числом")
}
}Строки
Строки не индексируются и не предоставляют .length. Доступ на уровне скаляров идёт через s.scalars(), возвращающий Array<string> из односкалярных строк.
let слово = "topaz"
let скаляры = слово.scalars() // ["t", "o", "p", "a", "z"]
let длина = слово.scalars().length // 5
print("Число скаляров: {длина}")Файлы и ресурсы
Операции с ресурсами являются Result-first. Откройте ресурс через ?, зарегистрируйте очистку через defer и верните результат последней операции.
function прочитатьТекст(путь: string) -> Result<string, string> {
let файл = open(путь)?
defer { файл.close() }
let содержимое = файл.read()?
Ok(содержимое)
}
function записатьТекст(путь: string, содержимое: string) -> Result<(), string> {
let файл = open(путь)?
defer { файл.close() }
файл.write(содержимое)
}JSON и Regex (зарезервированные имена)
JSON.parse и regex.match — зарезервированные имена стандартной библиотеки: они не входят в типизированный минимум, пока не специфицированы JSONValue, Regex и Match. Канонические примеры могут упоминать их только там, где форма возвращаемого значения не важна, с примечанием об отложенности. Не пишите код, зависящий от того, что они возвращают.
Regex значения-шаблоны каноничны уже сегодня через однострочную tagged-форму r"...":
let цифры = r"^[0-9]+$" // значение regex-шаблона (API сопоставления пока нет)Коллекции
Канонические конструкторы коллекций — Array.of, Map.new и Set.of. Изменяющие операции с коллекциями требуют mutable binding.
let mut числа = Array.of(1, 2, 3)
числа.push(4)
let количество = числа.length
let третий = числа[2] // 3 — прямая индексация даёт фолт вне границ
let безопасно = числа.get(10) // None — чтение без фолта, возвращает Option<int>
let естьЧетыре = 4 in числа
print("Количество: {количество}")
print("Третий: {третий}")
print("Есть четыре: {естьЧетыре}")arr.get — каноническое чтение без фолта; предпочитайте его всякий раз, когда индекс может выйти за границы.
let mut оценки: Map<string, int> = Map.new()
оценки.insert("alice", 10)
оценки.insert("bob", 20)
let оценкаAlice = оценки.get("alice") // Some(10) — None, если ключа нет
let удалено = оценки.remove("bob") // Some(20) — Some(старое) если был, иначе None
let знаетAlice = "alice" in оценки.keys // принадлежность идёт через представление keys
print("Есть alice: {знаетAlice}")m.keys — это снимок Array<K> в порядке вставки ключей: последующее изменение карты не меняет уже созданный массив ключей. Прямое x in map не канонично; используйте x in map.keys.
let mut теги = Set.of("docs")
теги.add("v5")
let естьDocs = "docs" in теги
let убрано = теги.remove("docs") // true, только если элемент был удалён
print("Есть docs: {естьDocs}")map, filter и reduce
map, filter и reduce — ordinary functions. Их сигнатуры — map(xs, f), filter(xs, f) и reduce(xs, initial, f): начальное значение идёт перед редьюсером. В pipelines передавайте piped value через _.
let числа = Array.of(1, 2, 3, 4, 5, 6)
let результат = числа
|> filter(_, x => x % 2 == 0)
|> map(_, x => x * x)
|> reduce(_, 0, (накоплено, x) => накоплено + x)
print("Сумма квадратов чётных: {результат}")Result helper-имена
Для восстанавливаемых ошибок используйте Ok, Err, match и распространение ?.
function загрузитьПорт(путь: string) -> Result<int, string> {
let содержимое = прочитатьТекст(путь)?
разобратьПорт(содержимое)
}
match загрузитьПорт("app.port") {
case Ok(порт) => print("Порт: {порт}")
case Err(ошибка) => print("Ошибка конфигурации: {ошибка}")
}Concurrent-блоки
concurrent возвращает запись результатов arm. В canonical public-примерах блок else должен возвращать fallback-запись той же shape.
function снимокПрофиля() -> { имя: string } {
{ имя: "Topaz" }
}
function недавняяАктивность() -> Array<string> {
Array.of("login", "edit")
}
function пустойПрофиль() -> { имя: string } {
{ имя: "offline" }
}
let панель = concurrent(timeout: 3s) {
профиль: снимокПрофиля()
активность: недавняяАктивность()
} else {
{
профиль: пустойПрофиль(),
активность: Array.of("offline")
}
}
print("Элементов активности: {панель.активность.length}")Tagged Templates
Tagged templates являются значениями. Shell template tag создаёт shell template value; он сам по себе не выполняет команду.
let имяПриложения = "topaz"
let idПользователя = 42
let директория = p"/var/{имяПриложения}"
let путьКонфига = p"/etc/{имяПриложения}/config.toml"
let цифры = r"^[0-9]+$"
let командаСписка = sh"ls {директория}"
let запрос = sql"select * from users where id = {idПользователя}"Эта страница намеренно узкая: если helper не перечислен здесь и не определён рядом с примером, не считайте его canonical Topaz public surface.