Перейти к содержанию

Ресурсные структуры: разбор целиком

Пользовательская структура может содержать move-only ресурсы: например, File, memory.Buffer<T>, vec.Vec<T>, ресурсный вариант или другую ресурсную структуру. Если хотя бы одно поле не копируется, вся структура move-only. Это расширение Core; специальный встроенный тип String не вводится.

struct Owner {buffer:memory.Buffer<u8>;length:u32}
fn wrap(buffer:memory.Buffer<u8>)->Owner {
    return Owner(move buffer,0)
}
fn release(owner:Owner)->u32 {
    (buffer,length)=move owner
    return memory.release(move buffer)
}

Владение и разбор

Разбор позиционный, в порядке объявления полей. Правая часть вычисляется один раз. Структура потребляется целиком, затем все поля получают отдельные новые привязки. Существующая именованная структура требует move. Временный результат конструктора или функции можно разобрать непосредственно.

Для одного поля требуется запятая: (handle,)=move owner. Для трёх и более полей используется (a,b,c)=move owner. Завершающая запятая допустима. Каждое поле нужно связать ровно один раз; _, повторные имена, переобъявление и вложенный шаблон запрещены. Для изменения владельца в цикле разберите его в новые привязки, соберите новую структуру и присвойте её исходной var.

Семантические операции остаются struct.construct, unpack.consume и unpack.component. Последние две теперь применимы также к ресурсным структурам, а не только к внутреннему линейному произведению. Новые операции LLVM и C runtime не требуются. Синтаксис обычного линейного результата остаётся совместимым.

Для owned-привязки первый срез намеренно не разрешает owner.field, move owner.field или обновление поля ресурсной структуры — даже если само поле копируемое. Это относится и к временной структуре: make_owner().length не может молча потерять ресурс. Нужно разобрать целого владельца и явно передать либо завершить ресурсные поля. Обычные копируемые структуры сохраняют прежние операции над полями.

Копирование, потеря ресурса при нормальном выходе, повторное использование после move и перезапись живого владельца запрещены. Ветви и обратные рёбра циклов должны сохранять согласованные обязанности владения. Trap не обещает cleanup.

Происхождение хранилища

Анализ сохраняет зависимости по каждому полю, включая вложенные структуры, generics, варианты и результаты функций. Два буфера из разных регионов не сливаются в один origin. После перестановки полей через функцию освобождение одного буфера разрешает закрыть только соответствующий регион.

Закрытие региона запрещено, пока зависимый буфер находится внутри структуры, нераспакованного варианта или временного аргумента. После разбора зависимость переходит соответствующему полю. Живой readonly view запрещает перемещение буфера в структуру; после извлечения буфера обычные правила заимствования продолжают действовать.

Самовладеющая пара «регион и зависимый от него буфер» не вводится. Прежнее правило запрещает move региона при живых зависимостях, в том числе внутри агрегата. Происхождения на поддерживаемых обратных рёбрах по-прежнему должны быть стабильны.

Приватность и границы

Разбор структуры доступен только там, где доступны все её поля. Приватный буфер нельзя извлечь через публичный тип: это позволяет обычному модулю поддерживать UTF-8 инвариант владеющей строки.

Readonly-параметры пользовательских структур теперь доступны в T2-A; они не дают права извлекать ресурсные поля во владение.

Ресурсные массивы, элементы Vec/Buffer с ресурсами, сохраняемые views, частичный move и автоматические деструкторы остаются вне этого среза. Внутренний Product нельзя хранить в структуре; публичного конструктора Product нет. Рекурсивные структуры по значению запрещены.

Изменение проверяется тестами типов, зависимостей и нативным исполнением O0/O2, включая большие вложенные поля. V0–V4 и Relay остаются проверками прежних выбранных программ: их успех не является доказательством soundness новых ресурсных структур.