Можно ли иметь модуль, который частично доступен снаружи ящика и частично только внутри ящика?

Есть ли лучший способ, чем просто положить все в один и тот же модуль?

sub_module.rs

pub struct GiantStruct { /* */ }

impl GiantStruct {

    // this method needs to be called from outside of the crate.
    pub fn do_stuff( /* */ ) { /* */ };
}

lib.rs

pub mod sub_module;
use sub_module::GiantStruct;

pub struct GiantStructBuilder{ /* */ }

impl GiantStructBuilder{
    pub fn new_giant_struct(&mut self) -> GiantStruct {
        // Do stuff depending on the fields of the current
        // GiantStructBuilder
    }
}

Проблема с GiantStructBuilder::new_giant_struct(); этот метод должен создать новый GiantStruct но для этого вам либо нужно pub fn new() -> GiantStruct Внутри sub_module.rs или все поля GiantStruct должен быть публичным. Оба варианта позволяют получить доступ снаружи моего ящика.

При написании этого вопроса я понял, что могу сделать что-то вроде этого:

sub_module.rs

pub struct GiantStruct { /* */ }

impl GiantStruct {
    // now you can't call this method without an appropriate
    // GiantStructBuilder
    pub fn new(&mut GiantStructBuilder) -> GiantStruct { /* */ };

    pub fn do_stuff( /* */ ) { /* */ };
}

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

1 ответ

Решение

Вы можете использовать недавно стабилизированный pub(restricted) конфиденциальность

Это позволит вам предоставлять типы / функции только ограниченному дереву модулей, например

pub struct GiantStruct { /* */ }

impl GiantStruct {
    // Only visible to functions in the same crate
    pub(crate) fn new() -> GiantStruct { /* */ };

    // this method needs to be called from outside of the crate.
    pub fn do_stuff( /* */ ) { /* */ };
}

Или вы можете применить это к полям на вашем GiantStruct чтобы позволить вам создать его из GiantStructBuilder:

pub struct GiantStruct { 
    pub(crate) my_field: u32,
}

Вместо crate Вы также можете использовать super указать, что это только для родительского модуля.

Другие вопросы по тегам