Menu

Zero Shapes: объявление struct-подобных записей

Shapes — это struct-подобные product-типы Zero. Как их объявить, конструировать значения, читать поля и пропускать через функции — с примерами из официальных образцов.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Объявление shape

shape — это тип-запись с именованными типизированными полями:

shape Point {
    x: i32,
    y: i32,
}

Части:

  • shape вводит объявление.
  • Point — имя типа.
  • Скобки оборачивают список полей, каждое — name: Type.

Это объявление добавляет в текущую область видимости новый тип под именем Point. Везде, где можно использовать встроенный тип вроде i32, теперь можно использовать и Point.

Конструирование значения shape

Создайте экземпляр через struct-литерал:

let point = Point { x: 40, y: 2 }

Литерал называет shape и присваивает каждое поле. Все поля должны присутствовать — Zero не подставляет тихо нули или null для пропущенных полей. Если одно забыли, компилятор скажет:

{
    "code": "FLD002",
    "message": "missing field: y",
    "line": 4
}

(Точный код ошибки может отличаться; принцип «без неявных умолчаний» постоянен.)

Тип можно прочитать или аннотировать явно, если хочется, чтобы он был видим:

let point: Point = Point { x: 40, y: 2 }

Чтение полей

Доступ к полям — через точку:

let point = Point { x: 40, y: 2 }
let xVal  = point.x
let yVal  = point.y

point.x читает поле x. Никаких методов get_x() — поля это просто данные.

Полный разобранный пример

Это каноничный пример point.0 из репозитория языка — нажмите Run, чтобы попробовать:

Пройдём сверху вниз:

  1. Объявляем shape Point с двумя полями i32.
  2. Определяем функцию sum, которая принимает Point и возвращает сумму его полей.
  3. В main конструируем Point, вызываем sum и сравниваем результат.

Три шага, три идеи, связанные с shape (объявить, сконструировать, обратиться), и один эффект — check world.out.write(...) в конце. Заметьте, что sum не трогает World. Это чистая функция над данными, и сигнатура это очевидно показывает.

Shapes с вложенными полями

Shape может хранить значения любого типа, включая другие shapes:

shape Range {
    start: i32,
    end: i32,
}

shape Segment {
    label: String,
    range: Range,
}

let seg = Segment {
    label: "warmup",
    range: Range { start: 0, end: 10 },
}

Доступ к полям цепляется как и ожидается:

let len = seg.range.end - seg.range.start

Дженерик-shapes

Когда поля shape должны быть типо-полиморфными, объявите параметры типа в угловых скобках:

shape Pair<T, U> {
    left: T,
    right: U,
}

Экземпляры фиксируют параметры конкретными типами:

let intBytePair: Pair<i32, u8> = Pair { left: 40, right: 2_u8 }
let words: Pair<String, String> = Pair { left: "hello", right: "world" }

Type alias может сократить частую параметризацию:

type BytePair = Pair<u8, u8>

let bytes: BytePair = Pair { left: 1_u8, right: 2_u8 }

Generics разбирает параметры типа глубже — в том числе на функциях, не только на shapes.

Чем shapes не являются

Несколько вещей, которые могут ожидаться от «структуры» в другом языке, но которых shapes намеренно не имеют:

  • Никаких методов. Объявление shape — это только данные. Поведение живёт в свободных функциях, которые принимают shape параметром. Это зеркалит то же разделение между данными и эффектами, что и в функциях.
  • Никакого наследования. Shapes не наследуются друг от друга. Если нужна общая структура, либо вынесите её в общее поле, либо стройте sum-тип через choice.
  • Никаких неявных конструкторов или деструкторов. Конструирование — это struct-литерал. Очистка — явная. Когда стандартная библиотека выставляет ресурсы, которые надо освобождать, это делается через capability-стиль API, а не через скрытый RAII.
  • Никаких приватных полей. Все поля shape доступны коду, который может видеть тип shape. Видимость — на уровне типа, а не поля.

Паттерн такой: shapes — простые предсказуемые типы-записи, из которых вы строите всё остальное.

Когда shape, а когда choice

Короткая шпаргалка:

  • Используйте shape, когда у значения все эти поля присутствуют вместе. У Point всегда есть и x, и y.
  • Используйте choice, когда значение — одно из нескольких альтернатив. Result — это или ok, или err.
  • Используйте enum, когда альтернативы не несут дополнительных данных — это просто метки. Дни недели, простые состояния.

Эти три строительных блока — shape (и), choice (или), enum (или без payload) — покрывают почти любую потребность в моделировании данных.

Дальше: Generics

Вы уже видели мельком Pair<T, U>. Следующая статья, generics, объясняет, как параметры типа работают и на shapes, и на функциях, включая паттерны, которые появляются по всей стандартной библиотеке Zero.

Часто задаваемые вопросы

Что такое shape в Zero?

shape — это struct-подобный product-тип в Zero, именованная запись с типизированными полями. Объявляете через shape Name { field1: T1, field2: T2 }, конструируете значения через Name { field1: v1, field2: v2 }, читаете поля через точку (value.field1). Shapes — строительный блок для моделирования структурированных данных.

Как создать значение shape?

Используйте struct-литерал, который называет shape и присваивает каждое поле: let point = Point { x: 40, y: 2 }. Каждое поле должно быть заполнено — Zero не подставляет тихо умолчания для пропущенных полей. Порядок полей в литерале не обязан совпадать с порядком в объявлении.

Чем shape отличается от класса?

Shape — это просто данные: есть поля, нет методов, нет наследования, нет неявных конструкторов. Функции, оперирующие shape, принимают его параметром явно. Это разделение держит язык маленьким и делает стоимость построения или копирования shape предсказуемой, без скрытых vtable или деструкторов.

Могут ли shapes быть дженериками в Zero?

Да. Объявите параметры типа в угловых скобках: shape Pair<T, U> { left: T, right: U }. Экземпляры закрепляют эти параметры: Pair<i32, u8>. Дженерик-shapes встречаются по всей стандартной библиотеке — Maybe<T>, Span<T> и так далее — всё это дженерик-shapes или sum-типы, построенные на той же идее.

Shapes копируются или передаются по ссылке в функции?

Передача по значению — дефолтная ментальная модель для shapes: вызываемая функция видит свою логическую копию данных, а не ссылку на привязку вызывающего. Точная модель памяти в pre-1.0 Zero ещё эволюционирует (в примерах стандартной библиотеки встретятся ref и mutref для явных типов ссылок). Для большинства прикладного кода считайте shape-параметры значениями.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ