Как я могу сделать индексируемую оболочку для обоих `Vec`и` & [i8] `? - PullRequest
0 голосов
/ 10 октября 2018

Рассмотрим следующий код:

use std::ops;

struct Wrap<T>(T);

impl<T> Wrap<T> {
    fn new(element: T) -> Self {
        Wrap(element)
    }
}

// implementation of other methods that makes the wrapper necessary ;-)

impl ops::Index<ops::Range<usize>> for Wrap<Vec<i8>> {
    type Output = Wrap<&[i8]>;

    fn index(&self, range: ops::Range<usize>) -> &Self::Output {
        &Wrap::<&[i8]>::new(&self.0[range])
    }
}

impl ops::Index<ops::Range<usize>> for Wrap<&[i8]> {
    type Output = Wrap<&[i8]>;

    fn index(&self, range: ops::Range<usize>) -> &Self::Output {
        &Wrap::<&[i8]>::new(&self.0[range])
    }
}

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

Состояние компилятора:

error[E0106]: missing lifetime specifier
  --> src/lib.rs:14:24
   |
14 |     type Output = Wrap<&[i8]>;
   |                        ^ expected lifetime parameter

error[E0106]: missing lifetime specifier
  --> src/lib.rs:21:45
   |
21 | impl ops::Index<ops::Range<usize>> for Wrap<&[i8]> {
   |                                             ^ expected lifetime parameter

error[E0106]: missing lifetime specifier
  --> src/lib.rs:22:24
   |
22 |     type Output = Wrap<&[i8]>;
   |                        ^ expected lifetime parameter

Как установить здесь время жизни?Я хочу, чтобы Wrap работал как для Vec, так и для заимствованных ломтиков.Что было бы лучшим решением?

Ответы [ 2 ]

0 голосов
/ 10 октября 2018

Этот оригинальный дизайн невозможен.Index ожидает, что метод index вернет ссылку на значение типа Self::Output:

fn index<'a>(&'a self, index: Idx) -> &'a Self::Output;

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

fn index<'a>(&'a self, range: ops::Range<usize>) -> &'a Self::Output {
    &Wrap::<&[i8]>::new(&self.0[range])
}

Это создает ссылку на Wrap объект, который живет только локально (и поэтому не переживает 'a).В этом случае потребовалась бы другая черта, такая как WrapIndex, которая, к сожалению, не содержала бы тот же синтаксический сахар.Он также не может быть обобщен без общих ассоциированных типов (GAT).

pub trait WrapIndex<Idx> where
    Idx: ?Sized, {
    type Output: ?Sized;
    fn wrap_index(&self, index: Idx) -> Wrap<&Self::Output>;
}

Если вы не возражаете, выставив все методы из типа среза в Wrap, вы также можете реализовать Deref для этой обертки, получая таким образом индексацию и нарезку бесплатно.

impl<T> Deref for Wrap<T>
where T: Deref
{
    type Target = <T as Deref>::Target;

    fn deref(&self) -> &Self::Target {
        self.0.deref()
    }
}
0 голосов
/ 10 октября 2018

Cow<[T]> - это, вероятно, то, что вам нужно:

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

use std::borrow::Cow;

fn main() {
    let w1: Cow<[i8]> = vec![1i8, 2, 3].into();
    let w2: Cow<[i8]> = (&[1i8, 2, 3][..]).into();

    println!("{:?}", &w1[1..2]);
    println!("{:?}", &w2[1..2]);
}

Это обеспечивает обертку, применимую как к собственным векторам, так и к заимствованным ломтикам без необходимости заново изобретать колесо:).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...