Hi all,
I'm a bit lost on implementing the Index
trait on a newtype type, and I think I might have inadvertently stumbled into unsafe territory.
Briefly, I have a type called FooBase
that I have defined using the newtype pattern. The new type is a wrapper around a Vec of values of type Bar. I'd like to slice instances of FooBase
into something that is Foo-like and that wraps a slice of type &[Bar].
So far I've implemented the slice as a new type called FooSlice
:
#[derive(Debug)]
struct FooBase(Vec<Bar>);
#[derive(Debug)]
struct FooSlice<'a>(&'a [Bar]);
Additionally, I've implemented a trait called Foo
because I would like to operate on both FooBase
s and FooSlice
s irrespective of what they are:
trait Foo {
fn bars(&self) -> &[Bar];
}
// ...
fn process_foos<T: Foo + Debug>(foos: T) {
println!("{:?}", foos.bars())
}
My problems arise when I try to implement the Index
trait so that I can write code such as
let foos = FooBase(vec![Bar, Bar, Bar, Bar, Bar]);
let foos_slice = &foos[1..3];
I've made an attempt at this, but I can't work out the lifetime annotations even with the compiler's help:
impl Index<Range<usize>> for FooBase {
type Output = FooSlice<'a>;
fn index(&self, range: Range<usize>) -> &Self::Output {
unsafe { std::mem::transmute(&FooSlice(&self.0[range])) }
}
}
leads to:
error[E0261]: use of undeclared lifetime name `'a`
--> src/main.rs:23:28
|
23 | type Output = FooSlice<'a>;
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'a` here
|
23 | type Output<'a> = FooSlice<'a>;
| ++++
help: consider introducing lifetime `'a` here
|
22 | impl<'a> Index<Range<usize>> for FooBase {
| ++++
For more information about this error, try `rustc --explain E0261`.
Could anyone help me understand whether what I want is possible, preferably with safe Rust?
Additionally, do you think this design even makes sense? Specifically, I wonder whether the type safety I get by wrapping the Vec<Bar>
in a new type is worth the trouble in slicing it. In my current project on which the above example is based, I have a few more methods defined on the new type wrapper FooBase
, but it would probably be alright to move these to functions instead.
Thanks everyone for your help!