Lifetimes for generalizing trait implementation from &T to AsRef<T> - rust

I have some problems generalizing a trait working for &str to other string types (e.g. Rc<str>, Box<str>,String).
First of all my example function should work for:
assert_eq!(count("ababbc", 'a'), 2); // already working
assert_eq!(count(Rc::from("ababbc"), 'a'), 2); // todo
assert_eq!(count("ababbc".to_string(), 'a'), 2); // todo
This is the working code, which makes the first test run:
pub trait Atom: Copy + Eq + Ord + Display + Debug {}
impl Atom for char {}
pub trait Atoms<A, I>
where
I: Iterator<Item = A>,
A: Atom,
{
fn atoms(&self) -> I;
}
impl<'a> Atoms<char, std::str::Chars<'a>> for &'a str {
fn atoms(&self) -> std::str::Chars<'a> {
self.chars()
}
}
pub fn count<I, A, T>(pattern: T, item: A) -> usize
where
A: Atom,
I: Iterator<Item = A>,
T: Atoms<A, I>,
{
pattern.atoms().filter(|i| *i == item).count()
}
To make the next tests run, I changed the signature of count and Atoms in following way:
pub trait Atoms<'a, A, I>
where
I: Iterator<Item = A> + 'a,
A: Atom,
{
fn atoms<'b>(&'b self) -> I
where
'b: 'a;
}
impl<'a, S> Atoms<'a, char, std::str::Chars<'a>> for S
where
S: AsRef<str> + 'a,
{
fn atoms<'b>(&'b self) -> std::str::Chars<'b>
where
'b: 'a,
{
self.as_ref().chars()
}
}
but now the function count does not compile any more:
pub fn count<'a, I, A, T>(pattern: T, item: A) -> usize
where
A: Atom,
I: Iterator<Item = A> + 'a,
T: Atoms<'a, A, I>,
{
pattern.atoms().filter(|i| *i == item).count()
}
Playground-Link
The compiler error is: the parameter type 'T' may not live long enough ... consider adding an explicit lifetime bound...: 'T: 'a'. This is not completely understandable for me, so I tried to apply the help T: Atoms<'a, A, I> + 'a. Now the error is: 'pattern' does not live long enough ... 'pattern' dropped here while still borrowed.
Since the latter error also occurs without implementations of Atoms and by just replacing the function body by pattern.atoms();return 1; I suspect that the type signature of Atoms is not suitable for my purpose.
Has anybody a hint what could be wrong with the type signature of Atoms or count?

trait Atoms<'a, A, I> where I: Iterator<Item = A> + 'a ...
By writing this, you're requiring the iterator to outlive the lifetime 'a. Since 'a is part of the trait's generic parameters, it must be a lifetime that extends before you start using (implicitly) <String as Atoms<'a, char, std::str::Chars>>::atoms. This directly contradicts the idea of returning a new iterator object, since that object did not exist before the call to atoms().
Unfortunately, I'm not sure how to rewrite this so that it will work, without generic associated types (a feature not yet stabilized), but I hope that at least this explanation of the problem helps.

I hope I clarify at least some parts of the problem. After doing some internet research on HRTBs and GATs I come to the conclusion that my problem is hardly solvable with stable rust.
The main problem is that one cannot
have a trait with different lifetime signature than its implementations
keep lifetimes generic in a trait for later instantiation in the implementation
limit the upper bound of a results lifetime if it is owned
I tried several approaches to but most evolve to fail:
at compiling the implementation (because the implementations lifetimes conflict with those of the trait)
at compiling the caller of the trait because a compiling implementation limits the lifetimes in a way, that no object can satisfy them.
At last I found two solutions:
Implement the trait for references
the function atoms(self) does now expect Self and not &Self
Atoms<A,I> is implemented for &'a str and &'a S where S:AsRef<str>
This gives us control of the lifetimes of the self objects ('a) and strips the lifetime completely from the trait.
The disadvantage of this approach is that we have to pass references to our count function even for smart references.
Playground-Link
use std::fmt::Display;
use std::fmt::Debug;
pub trait Atom: Copy + Eq + Ord + Display + Debug {}
impl Atom for char {}
pub trait Atoms<A, I>
where
I: Iterator<Item = A>,
A: Atom,
{
fn atoms(self) -> I;
}
impl<'a> Atoms<char, std::str::Chars<'a>> for &'a str {
fn atoms(self) -> std::str::Chars<'a> {
self.chars()
}
}
impl<'a, S> Atoms<char, std::str::Chars<'a>> for &'a S
where
S: AsRef<str>,
{
fn atoms(self) -> std::str::Chars<'a> {
self.as_ref().chars()
}
}
pub fn count<I, A, T>(pattern: T, item: A) -> usize
where
A: Atom,
I: Iterator<Item = A>,
T: Atoms<A, I>,
{
pattern.atoms().filter(|i| *i == item).count()
}
#[cfg(test)]
mod tests {
use std::rc::Rc;
use super::*;
#[test]
fn test_example() {
assert_eq!(count("ababbc", 'a'), 2);
assert_eq!(count(&"ababbc".to_string(), 'a'), 2);
assert_eq!(count(&Rc::from("ababbc"), 'a'), 2);
}
}
Switch to Generic Associated Types (unstable)
reduce the generic type Atoms<A,I> to an type Atoms<A> with an generic associated type I<'a> (which is instantiable at implementations)
now the function count can refer to the lifetime of I like this fn atoms<'a>(&'a self) -> Self::I<'a>
and all implementations just have to define how the want to map the lifetime 'a to their own lifetime (for example to Chars<'a>)
In this case we have all lifetime constraints in the trait, the implementation can consider to map this lifetime or ignore it. The trait, the implementation and the call site are concise and do not require references or helper lifetimes.
The disadvantage of this solution is that it is unstable, I do not know whether this means that runtime failures would probably occur or that api could change (or both). You will have to activate #![feature(generic_associated_types)] to let it run.
Playground-Link
use std::{fmt::Display, str::Chars};
use std::{fmt::Debug, rc::Rc};
pub trait Atom: Copy + Eq + Ord + Display + Debug {}
impl Atom for char {}
pub trait Atoms<A>
where
A: Atom,
{
type I<'a>: Iterator<Item = A>;
fn atoms<'a>(&'a self) -> Self::I<'a>;
}
impl Atoms<char> for str
{
type I<'a> = Chars<'a>;
fn atoms<'a>(&'a self) -> Chars<'a> {
self.chars()
}
}
impl <S> Atoms<char> for S
where
S: AsRef<str>,
{
type I<'a> = Chars<'a>;
fn atoms<'a>(&'a self) -> Chars<'a> {
self.as_ref().chars()
}
}
pub fn count<A, S>(pattern: S, item: A) -> usize
where
A: Atom,
S: Atoms<A>,
{
pattern.atoms().filter(|i| *i == item).count()
}
#[cfg(test)]
mod tests {
use std::rc::Rc;
use super::*;
#[test]
fn test_example() {
assert_eq!(count("ababbc", 'a'), 2);
assert_eq!(count("ababbc".to_string(), 'a'), 2);
assert_eq!(count(Rc::from("ababbc"), 'a'), 2);
}
}

Related

Rust - implementing trait for Deref: the parameter type `T` may not live long enough

I have a trait:
trait Foo {
fn bar(&self) -> Cow<str>;
}
And I want to implement it for any type that implements Deref with a target of a type that implements Foo. Basically:
impl<T: Foo, D: std::ops::Deref<Target = T>> Foo for D {
fn bar(&self) -> Cow<str> {
<T as Foo>::bar(std::ops::Deref::deref(self))
}
}
Unfortunately, this gives the error the parameter type T may not live long enough.
My understanding is that T could have a reference within it that has a short lifetime, and the lifetime bound of the return value of Cow<str> is linked to the lifetime of &self due to lifetime elision, which would cause problems.
I'm not sure how I can fix this, since I'm not able to bound any of the lifetimes in bar. I can try to make sure T lives as long as &self, but this doesn't work.
impl<'a, T: Foo + 'a, D: std::ops::Deref<Target = T>> Foo for D {
fn bar(&'a self) -> Cow<'a, str> {
<T as Foo>::bar(std::ops::Deref::deref(self))
}
}
I get the error method not compatible with trait since the lifetimes don't match the trait defenition anymore. I've tried all sorts of different ways of adding lifetime bounds and I always get one of those two errors.
I am able to implement Foo for a specific type that implements Deref:
impl<T: Foo> Foo for Box<T> {
fn bar(&self) -> Cow<str> {
<T as Foo>::bar(self)
}
}
I'm not sure why that works but the original example doesn't.
The Box version works because of the deref coercion the compiler will do when it sees a reference and expects a different reference.
You can use the same mechanic when using a generic implementor of Deref to ensure that it Derefs to an owned type you can simply add a 'static lifetime bound on T like this:
impl<T: Foo + 'static, D: std::ops::Deref<Target = T>> Foo for D {
fn bar(&self) -> Cow<str> {
<T as Foo>::bar(self)
}
}
playground
Note: there is rarely a need to call methods of std::ops traits directly, they're all just the methods behind Rusts operators, deref for example is the method behind unary *
Update:
Since there is an additional requirement that T might not be static we have to thread through the lifetime like you tried in your second example, like the error you're getting suggest you have to adjust the trait to take a lifetime as well:
use std::borrow::Cow;
trait Foo<'a> {
fn bar(&self) -> Cow<'a, str>;
}
impl<'a, T: Foo<'a>, D: std::ops::Deref<Target = T>> Foo<'a> for D {
fn bar(&self) -> Cow<'a, str> {
<T as Foo>::bar(self)
}
}
struct S<'a> {
val: &'a str,
}
impl<'a> Foo<'a> for S<'a> {
fn bar(&self) -> Cow<'a, str> {
todo!()
}
}
fn main() {
let val = String::from("test");
let s = S { val: &val }; // error: `val` does not live long enough
let b = Box::new(s);
let cow = Foo::bar(&b); // argument requires that `val` is borrowed for `'static`
}

Rust: implement trait for the associated type

In the snippet below (https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=5babd9991122c756e7afaa76da0b32f3)
#![feature(generic_associated_types)]
#![feature(marker_trait_attr)]
// StrSpan is opaque and imported from nom_locate
struct StrSpan<'a>(&'a str);
pub trait LifetimizedExt {
type Lifetimized<'a>;
}
impl<T> LifetimizedExt for Option<T>
where
T: LifetimizedExt
{
type Lifetimized<'a> = Option<T::Lifetimized<'a>>;
}
impl<'a,T> LifetimizedExt for &'a T
where
T: 'static + ?Sized
{
type Lifetimized<'b> = &'b T;
}
impl<'a,T> LifetimizedExt for &'a mut T
where
T: 'static + ?Sized
{
type Lifetimized<'b> = &'b mut T;
}
#[marker]
pub trait ParsableInput: LifetimizedExt {}
impl<'a> ParsableInput for &'a str {}
impl<'a> ParsableInput for StrSpan<'a> {}
impl<'a,I> ParsableInput for I::Lifetimized<'a>
where
I: ParsableInput
{}
specifically in
impl<'a,I> ParsableInput for I::Lifetimized<'a>
where
I: ParsableInput
{}
I is unconstrained.
According to https://doc.rust-lang.org/error-index.html#E0207,
Any type parameter of an impl must meet at least one of the following criteria:
it appears in the implementing type of the impl, e.g. impl Foo
for a trait impl,
it appears in the implemented trait, e.g. impl SomeTrait > for Foo
it is bound as an associated type, e.g. impl<T, U> SomeTrait for T where T: AnotherTrait<AssocType=U>
How do I rewrite the original snippet?
I always want to use ParsableInput trait to infer that I::Lifetimized<'a> is ParsableInput for any lifetime 'a. Is it possible?
Requested addition.
The reasons why such behavior is desired are that
It's just stating the important fact about the concerned types
Nom combinators require specific type signatures for functions to be used as their arguments.
They are generic as well. For example, line_ending. It requires T: InputIter + InputLength.
Without generic associated types, there will be too much repetition, and even one small combinatorial explosion (NxM implementations).
pub trait Parse<'a,I>: Sized
where
I: ParsableInput,
Self: LifetimizedExt<Lifetimized<'a> = Self>
{
/// Returns [`Result<P,E>`] where any [`Ok(p)`] is a pair `(i,val)`, s.t.
/// * `i` is the remaining input after parsing
/// * `val` is the parsed value
fn parse<'b, 'c>(i: I::Lifetimized<'b>) -> IResult<I::Lifetimized<'c>, Self::Lifetimized<'a>>
where
'b: 'c,
'b: 'a;
}
Addition #2: "Why LifetimizedExt exists"
Its associated generic type Lifetimized is the reification of the class of types equivalent to Self up to lifetime. I needed to make implementations of Parse::parse for (&'b str,&'c str) and for (StrSpan<'b>,StrSpan<'c>) (modulo other details). Theoretically, I could supply a pair-type-argument but (sic) parse wouldn't be generic.
Note: Now I realize that it could be generic if the constructed triple (&'a str,&'b str,&'c str) satisfied some trait but it would make things even more complicated.
Addition #3: "Why was genericity in Parse::parse needed"
There also was map_parsed_val function,
// Proper declaration and implementation requires GATs
use nom::IResult;
pub trait MapParsedValInTuple<'a, T>
where
for<'c> T: super::Parse<'a,&'c str>,
{
fn map_parsed_val<'b, U, F: FnOnce(T) -> U>(self, f: F) -> (&'b str, U)
where
'a: 'b;
}
impl<'a, T> MapParsedValInTuple<'a, T> for (&'a str, T)
where
for<'c> T: super::Parse<'a,&'c str>,
{
fn map_parsed_val<'b, U, F: FnOnce(T) -> U>(self, f: F) -> (&'b str, U)
where
'a: 'b,
{
let (remaining_input,parsed_val) = (self.0, self.1);
(remaining_input, f(parsed_val))
}
}
pub trait MapParsedValInResult<'a, T> {
fn map_parsed_val<'b, U, F: FnOnce(T) -> U>(self, f: F) -> IResult<&'b str, U>
where
'a: 'b;
}
impl<'a, T> MapParsedValInResult<'a, T> for IResult<&'a str, T> {
fn map_parsed_val<'b, U, F: FnOnce(T) -> U>(self, f: F) -> IResult<&'b str, U>
where
'a: 'b,
{
self.map(|(i, parsed_val)| (i, f(parsed_val)))
}
}
I haven't rewritten it yet but you can see that GATs would be nifty here. Also, you can notice that it deals only with types whose type-parameter for Parse is &str. With the addition of StrSpan, in this place too would happen combinatorial explosion. It's also important to note that it ends life of the parsed value while keeping the lifetime of the remaining input intact. How long they will live, how the function will be used, is unknown (and irrelevant as long as genericity in the method is there). It also makes sense that this method should be generic.

Using higher-ranked trait bounds with generics

I've stumbled upon an interesting edge case: using higher-ranked lifetime bounds to accept closures that return generic parameters, such as for<'a> FnOnce(&'a T) -> R: MyTrait. There's no way to specify that R lives for at most 'a. Perhaps it's best to explain with an example.
Let's define a simple reference-like type wrapping a value:
struct Source;
struct Ref<'a> {
source: &'a Source,
value: i32,
}
For convenience, let's add a helper constructor. Here I will use explicit lifetimes to make the borrowing self-explanatory:
impl Source {
fn new_ref<'a>(&'a self, value: i32) -> Ref<'a> {
Ref { source: self, value }
}
}
This is an extremely fancy implementation of a integer copying routine using HRTBs with a closure over our Ref:
fn call_1<F>(callback: F) -> i32
where
for<'a> F: FnOnce(&'a Source) -> Ref<'a>,
{
let source = Source;
callback(&source).value
}
fn fancy_copy_1(value: i32) -> i32 {
call_1(|s| s.new_ref(value))
}
This is fine and is working as expected. We know that Ref does not outlive the Source and the compiler is also able to pick it up. Now let's create a simple trait and implement it for our reference:
trait MyTrait {
fn value(&self) -> i32;
}
impl<'a> MyTrait for Ref<'a> {
fn value(&self) -> i32 {
self.value
}
}
And modify our integer copying routine to return a generic type implementing that trait instead of just returning Ref:
fn call_2<R, F>(callback: F) -> i32
where
for<'a> F: FnOnce(&'a Source) -> R,
R: MyTrait,
{
let source = Source;
callback(&source).value()
}
fn fancy_copy_2(value: i32) -> i32 {
call_2(|s| s.new_ref(value))
}
Suddenly I get an error: cannot infer an appropriate lifetime for autoref due to conflicting requirements. Rust playground link for convenience. That actually makes sense from some perspective: unlike with Ref<'a> in the first example I never said that R has to live for at most 'a. could very well live longer and thus have access to freed memory. So I need to annotate it with it's own lifetime. But there's no place to do it! The first instinct is to put the lifetime in the bounds:
where
for<'a> F: FnOnce(&'a Source) -> R,
R: MyTrait + 'a,
which is of course incorrect, as 'a is only defined for the first bound.
This is where I got confused, started searching and never found anything about combining HRTBs and generic types in one bound. Perhaps more experienced people in Rust have any suggestions?
Upd 1.
While I was thinking about the problem some more, I remembered I could use the impl Trait syntax. This looks like a solution to my problem:
fn call_3<F>(callback: F) -> i32
where
F: for<'a> FnOnce(&'a Source) -> (impl MyTrait + 'a),
{
let source = Source;
callback(&source).value()
}
fn fancy_copy_3(value: i32) -> i32 {
call_3(|s| Box::new(s.new_ref(value)))
}
That, however does not work because impl MyTrait is not allowed in this place for some reason (probably temporarily). But that made me think of dyn Trait syntax and that indeed does work!
fn call_4<F>(callback: F) -> i32
where
F: for<'a> FnOnce(&'a Source) -> Box<dyn MyTrait + 'a>,
{
let source = Source;
let value = callback(&source); // note how a temporary is required
value.value()
}
fn fancy_copy_4(value: i32) -> i32 {
call_4(|s| Box::new(s.new_ref(value)))
}
Here's my solution: with dyn Trait syntax there is a place to put the + 'a! Unfortunately this solution still doesn't quite work for me too well, as it requires object-safety on the trait plus adds an overhead of allocating a boxed value. But at least it's something.

How to avoid excessive cloning in Rust?

I'm trying to learn Rust, and like many before me set off to write a Fibonacci sequence iterator for practice. My first pass used u32s and worked fine, so I decided to try to write a generic version. This is my result:
use num::Integer;
use std::ops::Add;
pub struct Fibonacci<T: Integer + Add + Clone> {
nth: T,
n_plus_one_th: T,
}
impl<T: Integer + Add + Clone> Iterator for Fibonacci<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
let temp = self.nth.clone();
self.nth = self.n_plus_one_th.clone();
self.n_plus_one_th = temp.clone() + self.n_plus_one_th.clone();
Some(temp)
}
}
impl<T: Integer + Add + Clone> Fibonacci<T> {
pub fn new() -> Fibonacci<T> {
Fibonacci {
nth: T::one(),
n_plus_one_th: T::one(),
}
}
}
I tested this with a u32 and a num::BigUint, and it works fine. I'm concerned about all the cloning in the next method though. In particular, I don't understand why I need to clone during the addition step.
I suspect there is a better way to write this using some of Rust's more advanced reference concepts, but so far I haven't figured it out.
The solution is to use a where clause like so:
extern crate num;
use num::One;
use std::ops::Add;
pub struct Fibonacci<T> {
nth: T,
n_plus_one_th: T,
}
impl<T> Fibonacci<T>
where T: One
{
pub fn new() -> Fibonacci<T> {
Fibonacci {
nth: T::one(),
n_plus_one_th: T::one(),
}
}
}
impl<T> Iterator for Fibonacci<T>
where for<'a> &'a T: Add<&'a T, Output = T>
{
type Item = T;
fn next(&mut self) -> Option<T> {
use std::mem::swap;
let mut temp = &self.nth + &self.n_plus_one_th;
swap(&mut self.nth, &mut temp);
swap(&mut self.n_plus_one_th, &mut self.nth);
Some(temp)
}
}
Specifically, the for<'a> &'a T: Add<&'a T, Output=T> clause reads as "for any lifetime 'a, &'a T must implement Add with a RHS of &'a T and Output=T. That is, you can add two &Ts to get a new T.
With that, the only remaining issue is shuffling the values around, which can be done using swap.
I also took the liberty of simplifying the constraints elsewhere (you only needed One, not Integer).

Index and IndexMut implementations to return borrowed vectors

I've been working on a multi-dimensional array library, toying around with different interfaces, and ran into an issue I can't seem to solve. This may be a simple misunderstanding of lifetimes, but I've tried just about every solution I can think of, to no success.
The goal: implement the Index and IndexMut traits to return a borrowed vector from a 2d matrix, so this syntax can be used mat[rowind][colind].
A (very simplified) version of the data structure definition is below.
pub struct Matrix<T> {
shape: [uint, ..2],
dat: Vec<T>
}
impl<T: FromPrimitive+Clone> Matrix<T> {
pub fn new(shape: [uint, ..2]) -> Matrix<T> {
let size = shape.iter().fold(1, |a, &b| { a * b});
// println!("Creating MD array of size: {} and shape: {}", size, shape)
Matrix{
shape: shape,
dat: Vec::<T>::from_elem(size, FromPrimitive::from_uint(0u).expect("0 must be convertible to parameter type"))
}
}
pub fn mut_index(&mut self, index: uint) -> &mut [T] {
let base = index*self.shape[1];
self.dat.mut_slice(base, base + self.shape[1])
}
}
fn main(){
let mut m = Matrix::<f32>::new([4u,4]);
println!("{}", m.dat)
println!("{}", m.mut_index(3)[0])
}
The mut_index method works exactly as I would like the IndexMut trait to work, except of course that it doesn't have the syntax sugar. The first attempt at implementing IndexMut made me wonder, since it returns a borrowed reference to the specified type, I really want to specify [T] as a type, but it isn't a valid type. So the only option is to specify &mut [T] like this.
impl<T: FromPrimitive+Clone> IndexMut<uint, &mut [T]> for Matrix<T> {
fn index_mut(&mut self, index: &uint) -> &mut(&mut[T]) {
let base = index*self.shape[1];
&mut self.dat.mut_slice(base, base + self.shape[1])
}
}
This complains about a missing lifetime specifier on the trait impl line. So I try adding one.
impl<'a, T: FromPrimitive+Clone> IndexMut<uint, &'a mut [T]> for Matrix<T> {
fn index_mut(&'a mut self, index: &uint) -> &mut(&'a mut[T]) {
let base = index*self.shape[1];
&mut self.dat.mut_slice(base, base + self.shape[1])
}
}
Now I get method `index_mut` has an incompatible type for trait: expected concrete lifetime, but found bound lifetime parameter 'a [E0053]. Aside from this I've tried just about every combination of one and two lifetimes I can think of, as well as creating a secondary structure to hold a reference that is stored in the outer structure during the indexing operation so a reference to that can be returned instead, but that's not possible for Index. The final answer may just be that this isn't possible, given the response on this old github issue, but that would seem to be a problematic limitation of the Index and IndexMut traits. Is there something I'm missing?
At present, this is not possible, but when Dynamically Sized Types lands I believe it will become possible.
Let’s look at the signature:
pub trait IndexMut<Index, Result> {
fn index_mut<'a>(&'a mut self, index: &Index) -> &'a mut Result;
}
(Note the addition of the <'a> compared with what the docs say; I’ve filed #16228 about that.)
'a is an arbitrary lifetime, but it is important that it is specified on the method, not on the impl as a whole: it is in absolute truth a generic parameter to the method. I’ll show how it all comes out here with the names 'ρ₀ and 'ρ₁. So then, in this attempt:
impl<'ρ₀, T: FromPrimitive + Clone> IndexMut<uint, &'ρ₀ mut [T]> for Matrix<T> {
fn index_mut<'ρ₁>(&'ρ₁ mut self, index: &uint) -> &'ρ₁ mut &'ρ₀ mut [T] {
let base = index * self.shape[1];
&mut self.dat.mut_slice(base, base + self.shape[1])
}
}
This satisfies the requirements that (a) all lifetimes must be explicit in the impl header, and (b) that the method signature matches the trait definition: Index is uint and Result is &'ρ₀ mut [T]. Because 'ρ₀ is defined on the impl block (so that it can be used as a parameter there) and 'ρ₁ on the method (because that’s what the trait defines), 'ρ₀ and 'ρ₁ cannot be combined into a single named lifetime. (You could call them both 'a, but this is shadowing and does not change anything except for the introduction of a bit more confusion!)
However, this is not enough to have it all work, and it will indeed not compile, because 'ρ₀ is not tied to anything, nor is there to tie it to in the signature. And so you cannot cast self.data.mut_slice(…), which is of type &'ρ₁ mut [T], to &'ρ₀ mut [T] as the lifetimes do not match, nor is there any known subtyping relationship between them (that is, it cannot structurally be demonstrated that the lifetime 'ρ₀ is less than—a subtype of—'ρ₁; although the return type of the method would make that clear, it is not so at the basic type level, and so it is not permitted).
Now as it happens, IndexMut isn’t as useful as it should be anyway owing to #12825, as matrix[1] would always use IndexMut and never Index if you have implemented both. I’m not sure if that’s any consolation, though!
The solution comes in Dynamically Sized Types. When that is here, [T] will be a legitimate unsized type which can be used as the type for Result and so this will be the way to write it:
impl<T: FromPrimitive + Clone> IndexMut<uint, [T]> for Matrix<T> {
fn index_mut<'a>(&'a mut self, index: &uint) -> &'a mut [T] {
let base = index * self.shape[1];
&mut self.dat.mut_slice(base, base + self.shape[1])
}
}
… but that’s not here yet.
This code works in Rust 1.25.0 (and probably has for quite a while)
extern crate num;
use num::Zero;
pub struct Matrix<T> {
shape: [usize; 2],
dat: Vec<T>,
}
impl<T: Zero + Clone> Matrix<T> {
pub fn new(shape: [usize; 2]) -> Matrix<T> {
let size = shape.iter().product();
Matrix {
shape: shape,
dat: vec![T::zero(); size],
}
}
pub fn mut_index(&mut self, index: usize) -> &mut [T] {
let base = index * self.shape[1];
&mut self.dat[base..][..self.shape[1]]
}
}
fn main() {
let mut m = Matrix::<f32>::new([4; 2]);
println!("{:?}", m.dat);
println!("{}", m.mut_index(3)[0]);
}
You can enhance it to support Index and IndexMut:
use std::ops::{Index, IndexMut};
impl<T> Index<usize> for Matrix<T> {
type Output = [T];
fn index(&self, index: usize) -> &[T] {
let base = index * self.shape[1];
&self.dat[base..][..self.shape[1]]
}
}
impl<T> IndexMut<usize> for Matrix<T> {
fn index_mut(&mut self, index: usize) -> &mut [T] {
let base = index * self.shape[1];
&mut self.dat[base..][..self.shape[1]]
}
}
fn main() {
let mut m = Matrix::<f32>::new([4; 2]);
println!("{:?}", m.dat);
println!("{}", m[3][0]);
m[3][0] = 42.42;
println!("{:?}", m.dat);
println!("{}", m[3][0]);
}

Resources