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

Шаг 3. Данные: data и enum

Зачем#

Хорошая модель данных делает невозможные состояния непредставимыми. Для этого в OxL два основных строительных блока:

  • data — запись: «и то, и другое, и третье» (произведение типов). Пользователь — это имя и возраст и email.
  • enum — выбор: «или то, или другое» (сумма типов). Фигура — это круг или прямоугольник или точка, причём у каждого варианта свои поля.

Поведение (методы) пишется отдельно, в блоке impl, — так определение данных остаётся коротким и обозримым.

Пример#

oxl✓ проверяется в CI
@derive(Eq, Show)
data Point { x: i32; y: i32 }  // data — запись с именованными полями

impl Point {
  static fn origin() -> Point => Point{ x: 0, y: 0 }  // static fn — «конструктор»
  fn manhattan() -> i32 => x.abs() + y.abs()  // поля доступны по имени
  var fn moveBy(dx: i32, dy: i32) {  // var fn изменяет значение
    x += dx
    y += dy
  }
}

enum Shape {  // enum — сумма вариантов
  Circle(r: f64)
  Rect(w: f64, h: f64)
  Dot
}

fn describe(s: Shape) -> str =>
  match s {
    Circle(r) => "circle r={r}"
    Rect(w, h) => "rect {w}x{h}"
    Dot => "dot"
  }

fn main() io {
  var p = Point{ x: 3, y: -4 }
  print("{p.manhattan()}")
  p.moveBy(1, 1)
  print("{p}")
  print("{p == Point{ x: 4, y: -3 }} {Point.origin() == p}")
  for s in [Shape.Circle(1.5), Shape.Rect(2.0, 3.0), Shape.Dot] {
    print(describe(s))
  }
}
Вывод
7
Point{x: 4, y: -3}
true false
circle r=1.5
rect 2.0x3.0
dot

Разбор#

  • data Point { x: i32; y: i32 } — поля разделяются ; или переводом строки. Литерал записи: Point{ x: 3, y: -4 }. Все поля обязательны (если у поля нет значения по умолчанию).
  • @derive(Eq, Show) просит компилятор сгенерировать сравнение == и вывод в строку {p}. Доступны также Copy, Ord, Hash.
  • В impl Point методы видят поля по имени: x.abs() + y.abs(). static fn origin() вызывается как Point.origin().
  • var fn moveBy — метод, который изменяет значение; вызвать его можно только у var-переменной.
  • enum Shape { Circle(r: f64) … Dot } — варианты могут иметь поля или быть «пустыми». Создаются как Shape.Circle(1.5).
  • match s { … } разбирает вариант и достаёт поля. Подробно — в следующем шаге.

Типичные ошибки#

Забытое поле в литерале записи:

oxl✓ проверяется в CI
data User {
  id: u64
  name: str
}

fn main() {
  let u = User{ id: 1 }
}
error
missing-field

Диагностика missing-field называет недостающее поле. Опечатка в имени поля даёт unknown-field.

Забытый вариант в match (см. следующий шаг) — non-exhaustive: добавили новый вариант в enum — компилятор покажет все места, которые надо обновить.

Что запомнить#

  • data — «и», enum — «или»; методы живут в impl.
  • @derive избавляет от шаблонного кода.
  • Добавление варианта в enum ломает сборку везде, где match не учитывает его, — это защита, а не неудобство.

Дальше: сопоставление с образцом.

См. также

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