Как иметь личную часть черты? - PullRequest
0 голосов
/ 08 ноября 2018

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

Я хотел бы использовать черту, но не раскрывая реализацию. Например:

pub trait MyTrait {
    type Next;

    // This function is for the user.
    fn forward(&self) -> Self::Next {
        self.do_the_job()
    }

    // This function is for the user.
    fn stop(&self) {
        self.do_the_job();
    }

    // This function is an implementation detail.
    fn do_the_job(&self) -> Self::Next;
}

Я хочу, чтобы пользователь видел и использовал forward и stop, но не do_the_job, тогда как мои данные будут реализовывать только do_the_job.

Можно ли спроектировать мой код, чтобы сделать что-то подобное? Я пытался представить некоторые решения, но мне в голову ничего не пришло.

Детская площадка


На объектно-ориентированном языке с наследованием я бы сделал (псевдокод):

public interface MyTrait {
    type Next;

    fn forward(&self) -> Self::Next;

    fn stop(&self);
}

public abstract class MyCommonCode extends MyTrait {
    fn forward(&self) -> Self::Next {
        self.do_the_job()
    }

    fn stop(&self) {
        self.do_the_job();
    }

    protected abstract fn do_the_job(&self) -> Self::Next;
}

public MyType extends MyCommonCode {
    type Next = i32;

    protected override fn do_the_job(&self) -> Self::Next {
        // etc.
    }
}

1 Ответ

0 голосов
/ 08 ноября 2018

Черты похожи на интерфейсы :

Черты - единственное понятие интерфейса Rust.

Интерфейс предназначен для документирования доступных методов, иметь интерфейс с закрытыми методами не имеет смысла. Соответственно, в Rust вы не можете иметь разные уровни видимости в одной черте. Если вы можете видеть черту, вы всегда можете увидеть все это. Однако свойства Rust слегка отличаются от интерфейсов: они объединяют объявления и реализации. Я вижу, как было бы интуитивно иметь черту с некоторыми частными функциями.

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

Текущий обходной путь все еще разделяет черту, но приватная часть должна теперь быть представлена ​​публичной чертой в частном модуле. Чтобы объяснить это, вот пример кода:

// this module contains a public trait Inc, to increment a value
// and it implements it by using a private trait Add
mod my_math {
    pub struct Val {
        pub val: i32,
    }

    // this is necessary to encapsulate the private trait
    // the module is private, so the trait is not exported
    mod private_parts {
        pub trait Add {
            fn add(&mut self, i32);
        }
    }

    // in the following code, we have to use adequate namespacing
    impl private_parts::Add for Val {
        fn add(&mut self, other: i32) {
            self.val += other;
        }
    }

    pub trait Inc: private_parts::Add {
        fn inc(&mut self);
    }

    impl Inc for Val {
        fn inc(&mut self) {
            use my_math::private_parts::Add;
            self.add(1)
        }
    }
}

fn main() {
    use my_math::Inc;
    let mut b = my_math::Val { val: 3 };
    println!("value: {}", b.val);
    b.inc();
    println!("value: {}", b.val);
}
...