Какие свойства скрытого типа доступны вызывающему функции с возвращаемым impl Trait, если они не указаны в её bounds?
Вызывающий может использовать только те трейты и ограничения, которые объявлены в возвращаемом impl Trait. Конкретный тип скрыт: его нельзя напрямую назвать, вызвать его дополнительные методы или полагаться на дополнительные трейты без явного указания их в сигнатуре.
impl Trait в возвращаемой позиции не создаёт динамический trait object. Компилятор сохраняет конкретный тип и обычно использует статическую диспетчеризацию.
При проектировании библиотечного API часто требуется вернуть конкретную структуру, но не сделать её частью публичного контракта. Это особенно важно для итераторов и адаптеров: их реальные типы могут быть длинными, вложенными и изменяться при оптимизации реализации.
Возвращаемый impl Trait решает эту задачу: библиотека публикует необходимое поведение, а не внутреннее имя типа. При этом сохраняются преимущества статической типизации и статической диспетчеризации.
Если функция возвращает конкретный тип, вызывающий получает доступ ко всем его публичным возможностям, но API связывается с этим типом. Если возвращается dyn Trait, конкретный тип скрыт, однако появляется косвенный вызов через таблицу виртуальных методов и обычно требуется владение или ссылка подходящего размера.
impl Trait занимает промежуточное место: конкретный тип скрыт от вызывающего, но компилятор знает его внутри программы. Ошибка проектирования возникает, когда разработчик ожидает, что вызывающий сможет использовать любой фактический bound скрытого типа.
В возвращаемой позиции impl Trait означает один конкретный, но неименуемый тип, выбранный реализацией функции. Публичный контракт разрешает вызывающему только операции, соответствующие перечисленным bounds.
Например:
Вызов summary разрешён, потому что он входит в публичный bound. Но вызывающий не может обратиться к специфическим методам Report или объявить переменную типа Report, если это имя не экспортируется и не указано в контракте.
Все пути выполнения функции должны возвращать один и тот же конкретный тип. Поэтому impl Trait не предназначен для выбора разных типов в зависимости от условия. Для этого используют общий тип, например перечисление, либо Box<dyn Trait> с динамической диспетчеризацией.
Добавление дополнительного bound меняет возможности вызывающего и становится частью API. Например, -> impl Summary + Send позволяет передавать результат туда, где требуется Send; без такого обещания код клиента не должен рассчитывать на этот bound.
Библиотека возвращает цепочку адаптеров итератора. Вариант с конкретным типом даёт полную статическую информацию, но делает сигнатуру сложной и связывает клиентов с внутренней структурой. Вариант Box<dyn Iterator<Item = T>> скрывает тип и допускает разные реализации, однако требует выделения памяти и динамической диспетчеризации.
Выбран impl Iterator<Item = T>, потому что библиотека всегда возвращает один конкретный тип цепочки и не нуждается в выборе реализации во время выполнения. Клиент получает только контракт итератора, а библиотека может менять внутренние адаптеры без публикации их типа; при этом сохраняются мономорфизация и возможность оптимизации вызовов.
Если позднее потребуется возвращать разные типы итераторов по условию, impl Iterator уже не подойдёт без введения общего перечисления или перехода к Box<dyn Iterator<Item = T>>. Это компромисс между статической эффективностью и гибкостью представления.
Нет. Компилятор проверяет код клиента по опубликованному opaque-контракту, а не по фактическому типу, который функция возвращает внутри. Если такой метод нужен клиенту, соответствующий трейт следует добавить в возвращаемые bounds; иначе внутреннее изменение реализации не должно менять возможности клиента.
impl Trait?Нет. Все ветви должны иметь один и тот же конкретный тип, скрытый за impl Trait. Если варианты различаются, применяют перечисление с общей реализацией трейта, либо trait object; перечисление обычно сохраняет статическую диспетчеризацию, а trait object предоставляет большую расширяемость ценой косвенного вызова.
impl Trait динамическую диспетчеризацию?Нет. impl Trait скрывает тип на границе API, но не превращает его в dyn Trait. Компилятор знает конкретный тип и может мономорфизировать или встроить вызовы. Динамическая диспетчеризация появляется, когда используется сам trait object, например Box<dyn Trait> или &dyn Trait>, а не обычный возвращаемый impl Trait.