Приватный внутренний модуль, возвращающий приватный элемент, выдает ошибку «закрытый тип в публичном интерфейсе» - PullRequest
0 голосов
/ 08 июня 2018

В приведенном ниже примере модуль outer имеет закрытый тип Private и собственный внутренний модуль inner.inner может получить доступ к Private (поскольку дочерние модули могут обращаться к личным элементам своих родителей , даже если они не припаркованы как общедоступные).

inner определяет функцию not_really_public_interface().Хотя он помечен как общедоступный, он действительно доступен только для outer, поскольку сам inner не является общедоступным.

external.rs

struct Private;
mod inner {
  use super::Private;
  pub fn not_really_public_interface() -> Private {
    Private
  }
}

Компилируется без проблем.

outer должен иметь возможность использовать inner::not_really_public_interface() для получения Private, при условии, что он не экспортирует его.Итак, давайте сделаем это:

pub fn main() {
  let _ = self::inner::not_really_public_interface();
}

Правильно?

stderr

error[E0446]: private type `Private` in public interface
 --> src/outer.rs:4:3
  |
4 | /   pub fn not_really_public_interface() -> Private {
5 | |     Private
6 | |   }
  | |___^ can't leak private type

Wat. Это контр-Для меня это интуитивно понятно по нескольким причинам:

  • Прежний код не выдает ошибок, даже если он определяет функцию с интерфейсом, который Руст считает «утечкой».Ошибка возникает только тогда, когда outer пытается использовать эту функцию.
  • Единственное место, где inner может "утечь" Private, это модуль, который определилit .

Итак, мои вопросы:

  • Что именно здесь происходит, из-за чего Rust приходит к выводу, что какая-то часть этого интерфейса утечка?Кажется, что он обрабатывает Private, как если бы он был определен в inner.
  • Есть ли контекст, в котором это имеет смысл?Моей первой мыслью было, что это ошибка в компиляторе или недосмотр в дизайне конфиденциальности, но я сомневаюсь, что это так.
  • Есть ли способ обойти это без создания другого модуля?Я считаю, что могу создать модуль-обертку, а затем просто сделать Private общедоступным в outer и inner, но я бы предпочел не делать этого.

1 Ответ

0 голосов
/ 08 июня 2018

Функция not_really_public_interface является общедоступной, поэтому она может использоваться любым другим модулем.Но структура Private может быть доступна только вашим корневым и inner модулям.

Утечка произошла бы, если бы другой модуль импортировал not_really_public_interface.Rust жалуется, что это могло бы произойти, потому что оно сообщает об ошибках локально, а не рассматривает весь мир во всех случаях использования во всех модулях и ящиках.В конечном счете, этот подход более предсказуем для людей и позволяет быстрее рассуждать о машине.

Rust позволяет более точно контролировать видимость.Если вы скажете ему, что функция only доступна для модуля на один уровень выше (модуль super), то он узнает, что утечки нет:

mod inner {
    use super::Private;

    pub(super) fn not_really_public_interface() -> Private { Private }
}

Youможно также использовать crate вместо super, чтобы обозначать любой модуль в том же ящике.Или, если у супер-модуля есть имя, например, my_mod, вы можете использовать pub(in ::my_mod), чтобы указать его конкретно.

...