OxL Справочник OxL
РусскийEnglish

JSON и время

Туда и обратно#

Задача. Превратить структуру данных в JSON и прочитать её обратно.

oxl✓ проверяется в CI
use std.ser { toJson, fromJson }

enum Role { Admin; Member; Guest }

data Address { city: str; zip: str }

data User {
  id: i64
  name: str
  roles: List<Role>
  address: Address
  nickname: str?  // необязательное поле: none превращается в null
  tags: Map<str, str>
}

fn main() io {
  let u = User{
    id: 7, name: "Ann", roles: [Role.Admin, Role.Member],
    address: Address{ city: "Paris", zip: "75001" },
    nickname: none, tags: {"team": "core"},
  }
  let text = toJson(&u)!  // любой Serializable тип сериализуется без кода
  print(text)
  let back: User = fromJson(&text)!
  print("{back.name} {back.address.city} {back.roles.len()} {back.tags.get("team") ?? "-"}")
}
Вывод
{"id":"7","name":"Ann","roles":["Admin","Member"],"address":{"city":"Paris","zip":"75001"},"tags":{"team":"core"}}
Ann Paris 2 core
  • Тип сериализуем автоматически, если все его поля сериализуемы: data, enum, List, Map, T?, вложенные записи. Никаких аннотаций и кода не нужно.
  • toJson(&u) возвращает str | EncodeError, fromJson(&text) — T | DecodeError; тип результата задаётся аннотацией let back: User = … или явным fromJson<User>(…).
  • Пустой nickname: str? в JSON просто отсутствует. Целые 64-битные числа записываются строками ("id":"7") — так JSON безопасен для JavaScript, у которого числа — f64. Обратное чтение принимает оба вида.
  • Тот же код работает с форматами Msgpack и Cbor (std.ser): формат — параметр, а не отдельная библиотека.

Ошибки декодирования#

Задача. Принять данные из ненадёжного источника и не упасть.

oxl✓ проверяется в CI
use std.ser { fromJson }

data Point { x: i64; y: i64 }

fn parse(text: str) -> str {
  match fromJson<Point>(&text) {
    Point p => "ok {p.x},{p.y}"
    DecodeError => "decode error"  // DecodeError — обычная ошибка-значение
  }
}

fn main() io {
  print(parse("{{\"x\":1,\"y\":2}}"))
  print(parse("{{\"x\":1}}"))  // нет поля y
  print(parse("{{\"x\":\"one\",\"y\":2}}"))  // неверный тип
  print(parse("not json"))
}
Вывод
ok 1,2
decode error
decode error
decode error
  • Любая проблема — отсутствующее поле, неверный тип, синтаксис — даёт DecodeError; программа не паникует.
  • Уточнённые типы в полях (port: Port с where 1..=65535) проверяются при декодировании автоматически (§9.4), поэтому «валидация» часто сводится к выбору правильного типа.
  • В обработчике HTTP (рецепт) DecodeError превращается в ответ 400.

Даты и длительности#

Задача. Складывать длительности, считать календарные интервалы, не путаясь в високосных годах.

oxl✓ проверяется в CI
use std.time { Date }

fn main() io {
  let timeout = 90s + 500ms  // литералы Duration: ms, s, m, h, d
  print("{timeout.millis()} ms = {timeout.seconds()} s")
  print("{(2h + 30m).minutes()} minutes")
  let d = Date.of(2024, 2, 28)!
  print("{d.toIso()} {d.weekday()} leap: {d.isLeapYear()}")
  print("{d.plusDays(2).toIso()} {(d + 1.month()).toIso()}")
  let other = Date.of(2025, 1, 1)!
  print("{d.daysUntil(other)} days until {other.toIso()}")
  match Date.of(2023, 2, 30) {
    Date x => print("valid {x.toIso()}")
    InvalidValue => print("no such date")
  }
  match Duration.parse("1h30m") {
    Duration x => print("{x.minutes()}")
    ParseError => print("bad duration")
  }
}
Вывод
90500 ms = 90 s
150 minutes
2024-02-28 Wed leap: true
2024-03-01 2024-03-28
308 days until 2025-01-01
no such date
90
  • Литералы 90s, 500ms, 2h, 30m имеют тип Duration; они складываются и сравниваются. Единицы нельзя перепутать, потому что Duration — отдельный тип, а не число.
  • Date.of(2023, 2, 30) возвращает Date | InvalidValue: несуществующая дата не создаётся.
  • d + 1.month() — календарная арифметика (Period), а plusDays(n) — сдвиг на дни; Duration — это точное время (секунды), Period — календарное (месяцы, годы).
  • Для часовых поясов есть Tz и ZonedTime; std.time.now() читает часы и требует эффекта time, поэтому чистые функции получают время аргументом (и легко тестируются виртуальными часами, рецепт).

Вернуться: кулинарная книга.

См. также

OxL 1.0.0-beta · Версия документации 1.0.0-beta© OxwaldLink · сгенерировано из Стандарта, исходников std и руководства