Comment mettre en œuvre Itérateur et IntoIterator pour un simple struct?
Comment mettre en œuvre la Iterator
et IntoIterator
traits de la structure suivante?
struct Pixel {
r: i8,
g: i8,
b: i8,
}
J'ai essayé les diverses formes de la suivante, sans succès.
impl IntoIterator for Pixel {
type Item = i8;
type IntoIter = Iterator<Item=Self::Item>;
fn into_iter(self) -> Self::IntoIter {
[&self.r, &self.b, &self.g].into_iter()
}
}
Ce code me donne une erreur de compilation
error[E0277]: the trait bound `std::iter::Iterator<Item=i8> + 'static: std::marker::Sized` is not satisfied
--> src/main.rs:7:6
|
7 | impl IntoIterator for Pixel {
| ^^^^^^^^^^^^ the trait `std::marker::Sized` is not implemented for `std::iter::Iterator<Item=i8> + 'static`
|
= note: `std::iter::Iterator<Item=i8> + 'static` does not have a constant size known at compile-time
= note: required by `std::iter::IntoIterator`
Vous devez vous connecter pour publier un commentaire.
Votre itérateur de type est
Iterator<Item = Self::Item>
, maisIterator
est un trait de caractère. Les Traits sont mis en œuvre par les structures, ils n'existent pas sur leur propre. Vous pouvez aussi disposer d'une référence caractéristique de l'objet (&Iterator
), un coffret de trait de l'objet (Box<Iterator>
) ou un anonyme, un trait de mise en œuvre (impl Iterator
, qui ont toutes des formats connus.Au lieu de cela, nous créons un
PixelIntoIterator
qui a connu une taille et implémenteIterator
lui-même:C'est la belle prestation de retour réelle
i8
s, pas de références. Depuis qu'ils sont si petits, vous pourriez aussi bien les transmettre directement.Ce qui consomme de l'
Pixel
. Si vous avez eu une référence à unPixel
, vous devez également mettre en œuvre un itérateur qui n'est pas le consommer:Si vous voulais en charge la création de deux consommer un itérateur et un non-consommer de l'itérateur, vous pouvez mettre en œuvre les deux versions. Vous pouvez toujours prendre une référence à un
Pixel
vous propre, de sorte que vous ne besoin les non-consommatrices de variante. Toutefois, il est souvent agréable d'avoir une consommant version de sorte que vous pouvez retourner l'itérateur sans se soucier de la durée de vie.Il pourrait être un peu stupide, mais vous pouvez éviter la création de votre propre itérateur de type collage de certains types existants et l'utilisation impl trait:
[T; 3]
. Mais autant que je sache, vous ne pouvez pas sortir de tableaux. Au lieu de cela, vous pouvez le faire, mais il en coûte une allocation: est.gd/IMVLoGVec
est certainement une option, mais il semblait trop pour le ce struct.Option<[T; N]>
dans l'itérateur et écrire dessus avecNone
pour inhiber la baisse de la valeur interne. Le drop_in_place intrinsèque juste fusionné le rendra plus facile à l'avenir de la rouille.D'abord,
IntoIter
doit pointer vers un réelstruct
et non pas à untrait
pour que la Rouille pour être en mesure de passer la valeur autour de lui (qu'est ce queSized
moyens). Dans le cas des tableauxinto_iter
renvoie la std::trancher::Iterstruct
.Deuxième, typique d'un tableau,
[1, 2, 3]
, n'est pas alloué sur le tas. En fait, le compilateur est autorisé à optimiser loin de l'allocation entièrement, pointant vers un pré-compilé tableau à la place. Être en mesure de parcourir les tableaux sans les copier n'importe où, est je pense la raison pour laquelle leIntoIterator
mise en œuvre de tableaux de ne pas déplacer le tableau de n'importe où que les autresIntoIterator
des implémentations ne. Au lieu de cela, il semble référence le tableau existant. Vous pouvez voir à partir de sa signaturequ'il faut un référence à un tableau (
&'a [T; 3]
).En tant que tel, vous ne pouvez pas l'utiliser dans la façon dont vous essayez de. Référencé dans la matrice doit survivre le retour de l'itérateur. Voici une version où la Rouille compilateur dit donc.
Vecteur a une
IntoIterator
de mise en œuvre qui touche réellement les données dans l'itérateur et donc vous pouvez l'utiliser.P. S. Pour le rendre à la fois rapide et simple, retourner un tableau au lieu d'un itérateur (parc):
De cette façon, le tableau est d'abord déplacé dans l'extérieur de la portée et alors il peut être référencé partir de l'extérieur de la portée de l'itérateur:
vec!
ajoute une allocation de tas, c'est plus lent que Shepmaster de la version. Sur ma machine Shepmaster version (est.gd/BJUSbZ) exécute à 1 ns/iter.vec!
version (est.gd/CMNqzR) exécute à 23 ns/iter. Une version de retourner un tableau (est.gd/pr6Zaf) est à la fois simple et rapide à mettre en œuvre, il réalise à 1 ns/iter sur mon matériel.