Здравствуйте,
Есть структура с вектором. Нужно чтоб она возвращала срез. Куда мне посоветовали посмотреть - это на 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 работало. Любой способ подойдет лишь бы срез возвращало
Спасибо
Вопрос понятен. Чтобы вернуть срез необходимо в сигнатуре метода именно его и указать в качестве возвращаемого типа (&[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
Спасибо большое, Все работает!
Сразу не смог понять что такое &Self::Target из первого примера, потом понял что это то же самое что &[u8] Буду знать что и так писать можно
Self::Target это ассоциированный тип типажа (трэйта). Self указывает на сам тип(аж), оператор :: и капитализированный идентификатор после него на то что идет доступ к ассоциированному типу. Что такое ассоциированный тип лучше почитать в хорошей документации, я большой противник наспех разжевываемой в комментариях информации, относящейся к фундаментальным знаниям.
Как минимум такая запись удобна для рефакторинга: если тип таргета изменится, достаточно будет его поменять только в том месте, где он определен. Как максимум это удобно и для понимания кода, потому что видишь, что, ага, используется ассоциированный тип, а не какой-то произвольный.
Я наверное сюда и доспрошу… я не могу понять как может вернуть итератор срез. Код:
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
Согласно мнению экспертов прямого решения нет. RefCell в помощь.
Так как вы хотите - сделать нельзя. Потому что итератор (в текущем его виде в стандартной библиотеке 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.
Информативненько!
Сообщение должно быть не короче 20 символов.