Подтипы

39 views
Skip to first unread message

Mike Potanin

unread,
Dec 17, 2014, 4:34:23 AM12/17/14
to rust-r...@googlegroups.com

 Добрый день!
У меня есть два шаблона структуры S1<A> и S2<A,B>, и мне требуется держать в структуре S1<A> коллекцию ссылок на S2<A,*>, где * означает произвольный тип.
В С++ я мог бы унаследовать S2<A,B> от специального типа S2P<A>, и хранить в S1<A> коллекцию S2P<A>. По большому счету мне надо только уметь сравнивать ссылки на S2P<A> на равенство.
Возможно ли сделать что-то подобное в Rust?

Владимир Матвеев

unread,
Dec 17, 2014, 2:57:30 PM12/17/14
to rust-r...@googlegroups.com
Добрый вечер!

В Rust нет сабтайпинга, как и нет понятия равенства ссылок - отношение равенства определено только над значениями и "проходит сквозь" ссылки. Поэтому если пытаться реализовать ваш подход непосредственно, и если вам на самом деле нужно *только* сравнивать сыылки, то вам придётся использовать сырые указатели, и в этом случае отношение подтипов совершенно не нужно:

    struct S2<A, B>;

    struct S1<A> {
        refs: Vec<*const ()>
    }

    impl<A> S1<A> {
        fn new() -> S1<A> {
            S1 { refs: Vec::new() }
        }

        fn push<B>(&mut self, r: &S2<A, B>) {
            self.refs.push(r as *const _ as *const ());
        }

        fn compare(&self, i1: uint, i2: uint) -> bool {
            self.refs[i1] == self.refs[i2]
        }
    }

    fn main() {
        let mut s: S1<int> = S1::new();

        let x: S2<int, f64> = S2;
        let y: S2<int, String> = S2;

        s.push(&x);
        s.push(&x);
        s.push(&y);

        println!("{}", s.compare(0, 1));
        println!("{}", s.compare(0, 2));
    }

Это, однако, очень сомнительный подход - в Rust равенство ссылок не определено, и вообще ссылки очень хрупки. Из-за того, что в этом коде они преобразовываются в сырые указатели, информация о их времени жизни недоступна внутри S1, поэтому они могут легко стать "висячими". Пока вы не разыменовываете их (для этого потребуется unsafe-блок), вы не получите сегфолтов и прочих пакостей, но логика программы в целом может пострадать. Кроме того, в этом случае вы не сможете безопасно получить доступ к самим объектам типа S2<A, *> в принципе.

Общего способа же абстрагироваться от одного типового параметра я не знаю. Вы можете использовать Any (если все ваши типы S2<A, *> являются 'static), но в этом случае вам придётся делать downcast каждый раз, когда вам понадобится работать с объектами этого типа непосредственно. По идее, здесь могло бы помочь наследование трейтов:

trait S2P<A> : Any {}

Downcast бы всё равно потребовался, но типы можно было бы задать более строго. Однако наследование пока не работает правильно вместе с trait objects, которые здесь тоже понадобятся, поэтому вам это не подойдёт.

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

среда, 17 декабря 2014 г., 10:34:23 UTC+1 пользователь Mike Potanin написал:

Mike Potanin

unread,
Dec 17, 2014, 3:18:31 PM12/17/14
to rust-r...@googlegroups.com

Я пытаюсь реализовать сигналы/слоты, как в Boost и Qt. Время жизни сигналов и слотов, по моему опыту их использования, должно быть независимо - по этому я использую сырые указатели. Эта конструкция понадобилась, что бы отцепить слот от сигнала при возможности соединять слот с разными сигналами (с разной политикой агрегацией ответов).
Одним сравнением ограничится похоже не удается.

Vladimir Matveev

unread,
Dec 17, 2014, 3:42:13 PM12/17/14
to Mike Potanin, rust-r...@googlegroups.com
Мда, в этом случае, я боюсь, я мало чем смогу помочь. У меня нет опыта
в реализации подобных вещей, поэтому я не знаю, как они устроены, но у
меня очень серьёзные подозрения, что без unsafe в сколько-нибудь
производительной реализации в любом случае не обойтись. Здесь вам,
вероятно, будет полезнее спросить на английском в /r/rust на реддите
про общие подходы, там много знающих людей, в том числе с бэкграундом
в C++ (я к таким не отношусь :)).

17 декабря 2014 г., 21:18 пользователь Mike Potanin
<mpot...@gmail.com> написал:
> --
> Вы получили это сообщение, поскольку подписаны на группу "Rust по-русски".
> Чтобы отменить подписку на эту группу и больше не получать от нее сообщения,
> отправьте письмо на электронный адрес
> rust-russian...@googlegroups.com.
> Чтобы посмотреть обсуждение на веб-странице, перейдите по ссылке
> https://groups.google.com/d/msgid/rust-russian/591e5e15-8710-4261-9b1c-060ea3dceb16%40googlegroups.com.
>
> Чтобы настроить другие параметры, перейдите по ссылке
> https://groups.google.com/d/optout.

Mike Potanin

unread,
Dec 18, 2014, 5:17:43 AM12/18/14
to rust-r...@googlegroups.com, mpot...@gmail.com

Спасибо за советы!
Если сам не справлюсь, придется подучить английский :-).

А можно описать массив, про который в одном месте был бы известен точный тип его элементов, а в другом, на чтение, - только принадлежность к некоторым трейтам?

Vladimir Matveev

unread,
Dec 18, 2014, 5:25:34 AM12/18/14
to Mike Potanin, rust-r...@googlegroups.com

Нет, так сделать нельзя. Вернее, если вам известен точный тип элементов массива, то и принадлежность к трейтам также известна. В обратном направлении не работает.

18 Дек 2014 г. 11:17 пользователь "Mike Potanin" <mpot...@gmail.com> написал:
Чтобы посмотреть обсуждение на веб-странице, перейдите по ссылке https://groups.google.com/d/msgid/rust-russian/61b8a09d-537c-4cbe-8eb0-a30a991c0a64%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages