Используйте модули, когда у одного файла есть чёткая задача, а другому файлу
нужен его результат. Каждый файл .tpz является отдельным модулем; особого
объявления module нет.
Соберите одну программу из двух файлов
Исходные файлы приложения учебного плана расположены так:
study-plan/
├── topaz.toml
├── topaz.lock
└── src/
├── main.tpz
└── plan.tpzsrc/plan.tpz отвечает за модель данных и повторно используемые операции:
export record StudyTask {
title: string,
minutes: int,
done: bool = false,
}
function parseMinutes(text: string) -> Result<int, string> {
match toInt(text) {
case Some(value) if value > 0 => Ok(value)
case _ => Err("minutes must be a positive integer")
}
}
export function makeTask(
title: string,
minuteText: string,
done: bool = false,
) -> Result<StudyTask, string> {
let minutes = parseMinutes(minuteText)?
Ok(StudyTask { title: title, minutes: minutes, done: done })
}
export function summarize(tasks: Array<StudyTask>) -> string {
let mut remaining = 0
for task in tasks {
if !task.done {
remaining = remaining + task.minutes
}
}
"tasks={tasks.length}, remaining={remaining} minutes"
}src/main.tpz выбирает три нужных ему имени:
import src.plan { StudyTask, makeTask, summarize }
export function main(args: Array<string>, stdin: string) -> Result<int, string> {
let tasks: Array<StudyTask> = [
makeTask("Run first program", "10", true)?,
makeTask("Build application", "25", false)?,
]
print(summarize(tasks))
Ok(0)
}Из корня пакета проверьте и запустите разрешённую единицу компиляции:
topaz check --root . --locked
topaz run --root . --locked
tasks=2, remaining=25 minutesПри явно заданном корне путь src.plan соответствует файлу
src/plan.tpz. Единица компиляции состоит из точки входа и всех модулей,
достижимых по цепочке импортов. Файлы вне этой цепочки для данной точки входа
не проверяются.
Экспортируйте только нужную границу
Имя остаётся закрытым, если перед его объявлением нет export.
StudyTask, makeTask и summarize пересекают границу модуля, а
parseMinutes остаётся деталью реализации. Попытка выбрать или прочитать его
из src/main.tpz приводит к статической ошибке. Импортированные привязки
доступны только для чтения.
Выборочный импорт привязывает экспортированные имена напрямую:
| Задача | Каноническая форма |
|---|---|
| Выбрать несколько имён | import src.plan { StudyTask, makeTask } |
| Переименовать выбранное имя | import src.plan { summarize as renderSummary } |
| Привязать пространство имён | import src.plan as plan |
При импорте пространства имён экспортированные значения доступны как
plan.makeTask(...). Пространство имён служит для разрешения имён во время
компиляции и не является значением программы. Экспортированный тип
plan.StudyTask допустим в позиции типа, но запись
plan.StudyTask { ... } не создаёт значение. Для прямого создания именной
записи выберите StudyTask отдельным импортом.
Исправление частой ошибки: формы нельзя объединить в
import src.plan as plan { summarize }. Выберите либо импорт пространства
имён, либо выборочный импорт.
Корень, инициализация и пакет — разные решения
- Путь модуля — это разделённый точками адрес под выбранным корнем. Имена файлов и каталогов должны совпадать точно.
- Все импорты образуют пролог верхнего уровня и располагаются перед остальными элементами.
- Зависимый модуль инициализируется один раз до импортирующего его модуля. Импортируемый модуль может содержать объявления и привязки, но не свободные исполняемые инструкции верхнего уровня, например цикл или присваивание.
topaz.tomlзадаёт для инструментов имя пакета, точку входа, зависимости и цель сборки. Он не вводит ещё один синтаксис объявления модулей.
Как в примере выше, команда пакета может предоставить точку входа и корень.
Если файл указан напрямую, его каталог служит корнем по умолчанию; параметр
--root позволяет явно выбрать содержащий его корень.
Циклические импорты отклоняются
Предположим, a.tpz импортирует b.tpz:
import b
export function fromA() -> int {
1
}а b.tpz импортирует a.tpz:
import a
export function fromB() -> int {
2
}Команда topaz check a.tpz --root . сообщает о проверенном цикле:
error[TPZ3006]: import cycle: a -> b -> a
--> a.tpz:1:8
|
1 | import b
| ^
a.tpz: 1 diagnosticКаждое ребро импорта участвует в проверке, даже если импортированное имя используется только как тип. Разорвите цикл: перенесите общие объявления в третий ациклический модуль или оставьте зависимость только в одном направлении. Исключения для циклов, содержащих только типы, нет.
Точные границы
Текущий синтаксис модулей не включает use, строковые или шаблонные пути,
одновременные псевдоним и список выбора, списки экспорта, групповой экспорт,
повторный экспорт, переименование на месте экспорта и импорт только ради
побочного эффекта. export let mut также отклоняется. Импорт не может выйти
за пределы корня, а пространство имён не открывает закрытые члены.
Продолжите с Первым приложением, чтобы собрать полностью проверенный пакет, с разделом Пакеты и распространение для манифеста и файла блокировки и со страницей Запрещённые и отложенные формы для знакомых форм модулей, которые Топаз намеренно не принимает.