Структура которая возвращает slice (срез) на self вектор


#1

Здравствуйте,

Есть структура с вектором. Нужно чтоб она возвращала срез. Куда мне посоветовали посмотреть - это на deref. Код:

struct DerefExample {
    value: Vec<u8>
}

impl Deref for DerefExample {
    type Target = Vec<u8>;

    fn deref(&self) -> &Vec<u8> {
        // а так не работает
        // &self.value[..3]

        &self.value
    }
}


fn main() {
    let der = DerefExample {
        value: vec![0, 1, 2, 3, 4, 5, 6, 7]
    };

    println!("{:?}", der.value);
}

Playground

Мне не обязательно чтоб через deref работало. Любой способ подойдет лишь бы срез возвращало

Спасибо


#2

оно?


#3

Вопрос понятен. Чтобы вернуть срез необходимо в сигнатуре метода именно его и указать в качестве возвращаемого типа (&[T]).

Полноценный пример:

struct A {
    pub b: Vec<u8>,
}

impl A {
    
    fn test(&self) -> &[u8] {
        &self.b
    }
}

fn main() {
    let a = A { b: vec![1,2,3] };
    println!("{:?}", a.test());
}

Ссылка на плэйграунд: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=97499003e02e24a9816a9d306362a580

Больше о слайсах можно узнать в соответствующем разделе книги: https://doc.rust-lang.org/book/ch04-03-slices.html#other-slices, а так же из официальной документации: https://doc.rust-lang.org/std/slice/index.html


#4

Спасибо большое, Все работает!

Сразу не смог понять что такое &Self::Target из первого примера, потом понял что это то же самое что &[u8] Буду знать что и так писать можно


#5

Self::Target это ассоциированный тип типажа (трэйта). Self указывает на сам тип(аж), оператор :: и капитализированный идентификатор после него на то что идет доступ к ассоциированному типу. Что такое ассоциированный тип лучше почитать в хорошей документации, я большой противник наспех разжевываемой в комментариях информации, относящейся к фундаментальным знаниям.
Как минимум такая запись удобна для рефакторинга: если тип таргета изменится, достаточно будет его поменять только в том месте, где он определен. Как максимум это удобно и для понимания кода, потому что видишь, что, ага, используется ассоциированный тип, а не какой-то произвольный.


#6

Я наверное сюда и доспрошу… я не могу понять как может вернуть итератор срез. Код:

use std::marker::PhantomData;

#[allow(dead_code)]

struct DerefExample<'a> {
    value: Vec<u8>,
    phantom: PhantomData<&'a u8>,
}

impl<'a> Iterator for DerefExample<'a> {
    type Item = &'a [u8];

    fn next(&mut self) -> Option<Self::Item> {
        // а такой код не работает
        //Some(&self.value[..3])

        None
    }
}


fn main() {
    let mut der = DerefExample {
        value: vec![0, 1, 2, 3, 4, 5, 6, 7],
        phantom: PhantomData,
    };

    println!("{:?}", der.next());
}

Rust Playground


#7

Согласно мнению экспертов прямого решения нет. RefCell в помощь.


#8

Так как вы хотите - сделать нельзя. Потому что итератор (в текущем его виде в стандартной библиотеке Rust) не может вернуть ссылку на данные, которыми он владеет (нет связи времён жизни между возвращаемым значением в сигнатуре функции next и ассоциированным типом). Поэтому в std и в различных крейтах - в большинстве случаев есть промежуточный тип, который не владеет данными и для которого и реализуется Iterator, а создаётя этот промежуточный тип с помощью имплементации на типе IntoIterator. В вашем случае тип данных является владельцем данных и для него же производится попытка реализовать трэйт Iterator.

Пример того, как можно сделать:

struct Example {
    value: Vec<u8>,
}

struct IteratorExample<'a> {
    value: &'a [u8],
}

impl<'a> Iterator for IteratorExample<'a> {
    type Item = &'a [u8];

    fn next(&mut self) -> Option<Self::Item> {
        // а такой код не работает
        Some(&self.value[..3])
        
        // None
    }
}

impl<'a> IntoIterator for &'a Example {
    type Item = &'a [u8];
    type IntoIter = IteratorExample<'a>;
    
    fn into_iter(self) -> Self::IntoIter {
        IteratorExample {
            value: &self.value
        }
    }
    
} 

fn main() {
    let der = Example {
        value: vec![0, 1, 2, 3, 4, 5, 6, 7],
    };
    let mut iter = der.into_iter();
    println!("{:?}", iter.next());
    println!("{:?}", iter.next());
    println!("{:?}", iter.next());
    
}

Ссылка на плэйграунд:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=a3bb6ad1b94290c23978a239393dc54d

P.S
А теперь ссылка касательно того, почему сейчас этого сделать нельзя: https://github.com/rust-lang/rfcs/blob/master/text/1598-generic_associated_types.md#motivation
Ждём конструкторов ассоциированных типов (часть HKT). В найтли это уже есть и можно опробовать с помощью включения флага: #![feature(generic_associated_types)]
Оно пока анстейбл и может вызывать поломку компилятора. И даже в том случае, если это реализуют и стабилизируют, не понятно когда стриминг итераторы заедут в std.


#9

Информативненько!
Сообщение должно быть не короче 20 символов.