This may simply be that I'm misunderstanding something. But I was surprised by the workaround necessary to make the following code work. When working on the Xorcism exercise in Exercism, I needed to return an impl Iterator<Item=u8>. This was complicated by the presence of two different lifetime parameters (the 'a parameter from the trait for the key field, which is a &'a [u8], and the 'b parameter for the &'b mut self). With the following initial code:
use std::borrow::Borrow;
#[derive(Clone)]
pub struct Xorcism<'a> {
key: &'a [u8],
index: usize,
}
pub trait MungeOutput: Iterator<Item = u8> + ExactSizeIterator {}
impl<'a, T> MungeOutput for T where T: Iterator<Item = u8> + ExactSizeIterator {}
fn next_key(key: &[u8], index: &mut usize) -> u8 {
let b = key[*index];
*index += 1;
if *index >= key.len() {
*index = 0;
}
b
}
impl<'a> Xorcism<'a> {
pub fn new<Key: AsRef<[u8]> + ?Sized>(key: &'a Key) -> Xorcism<'a> {
Xorcism {
key: key.as_ref(),
index: 0,
}
}
pub fn munge_in_place(&mut self, data: &mut [u8]) {
for b in data {
*b ^= next_key(self.key, &mut self.index);
}
}
pub fn munge<'b, Data>(&'b mut self, data: Data) -> impl Iterator<Item=u8> + 'b
where
Data: IntoIterator,
Data::Item: Borrow<u8>,
Data::IntoIter: 'b,
{
data.into_iter().map(move |b| *b.borrow() ^ next_key(&self.key, &mut self.index))
}
}
I got the error message:
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> src\lib.rs:35:57
|
35 | pub fn munge<'b, Data>(&'b mut self, data: Data) -> impl Iterator<Item=u8> + 'b
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: hidden type `Map<<Data as IntoIterator>::IntoIter, [closure@src\lib.rs:41:30: 41:89]>` captures the lifetime `'a` as defined on the impl at 21:6
--> src\lib.rs:21:6
|
21 | impl<'a> Xorcism<'a> {
| ^^
However, if I replaced the line:
data.into_iter().map(move |b| *b.borrow() ^ next_key(&self.key, &mut self.index))
With the non-obvious and less intuitive:
let key = &self.key;
let index = &mut self.index;
data.into_iter().map(move |b| *b.borrow() ^ next_key(key, index))
The code compiled and ran as expected. I may be missing something, but I can't see a reason why borrowing the fields from the structure would be safe, but borrowing the structure itself would be dangerous.
Note that the original goal was to make next_key a method of the Xorcism struct, so that the best version of the code would read:
data.into_iter().map(move |b| *b.borrow() ^ self.next_key())
Meta
rustc --version --verbose:
> rustc --version --verbose
rustc 1.48.0 (7eac88abb 2020-11-16)
binary: rustc
commit-hash: 7eac88abb2e57e752f3302f02be5f3ce3d7adfb4
commit-date: 2020-11-16
host: x86_64-pc-windows-msvc
release: 1.48.0
LLVM version: 11.0
Also occurs on nightly:
> rustc +nightly --version --verbose
rustc 1.51.0-nightly (158f8d034 2020-12-29)
binary: rustc
commit-hash: 158f8d034b15e65ba8dc0d066358dd0632bfcd6e
commit-date: 2020-12-29
host: x86_64-pc-windows-msvc
release: 1.51.0-nightly
This may simply be that I'm misunderstanding something. But I was surprised by the workaround necessary to make the following code work. When working on the Xorcism exercise in Exercism, I needed to return an
impl Iterator<Item=u8>. This was complicated by the presence of two different lifetime parameters (the'aparameter from the trait for thekeyfield, which is a&'a [u8], and the'bparameter for the&'b mut self). With the following initial code:I got the error message:
However, if I replaced the line:
With the non-obvious and less intuitive:
The code compiled and ran as expected. I may be missing something, but I can't see a reason why borrowing the fields from the structure would be safe, but borrowing the structure itself would be dangerous.
Note that the original goal was to make
next_keya method of theXorcismstruct, so that the best version of the code would read:Meta
rustc --version --verbose:Also occurs on nightly: