Hi folks,
I'm trying to better understand the meaning of bounds on the definition of a trait. Concretely, I'm fighting this in a context where I want my trait to have IndexMut<...>
as a supertrait (which has Index<...>
as a supertrait), but also require that the associated type Index<...>::Output
satisfies From<f64>
so that I can assign f64
values via the mutable index.
My confusion is highlighted in this playground, reproduced below.
use std::ops::{Index,IndexMut};
// I want something like this to mean "MatrixTrait can only be implemented if
// IndexMut is also implemented SATISFYING THE TRAIT BOUND", but it does not
// appear to be so, otherwise line (*) below would already be implied.
trait MatrixTrait: IndexMut<(usize,usize)>
where
<Self as Index<(usize,usize)>>::Output : From<f64>
{
}
struct Matrix {
data: [[f64; 3]; 3]
}
impl Index<(usize,usize)> for Matrix {
type Output = f64;
fn index(&self, (i,j): (usize,usize)) -> &Self::Output {
&self.data[i][j]
}
}
impl IndexMut<(usize,usize)> for Matrix {
fn index_mut(&mut self, (i,j): (usize,usize)) -> &mut Self::Output {
&mut self.data[i][j]
}
}
impl MatrixTrait for Matrix {
}
fn act_on_matrix<T>(U: &mut T) -> ()
where
T : MatrixTrait,
// will not compile if (*) is commented out
// <T as Index<(usize,usize)>>::Output : From<f64> // (*)
{
U[(1,1)] = 0.0.into();
}
fn main() -> () {
let mut U = Matrix{data: [[0_f64; 3]; 3]};
act_on_matrix(&mut U);
}
In this example, I would have expected the bound on the definition of MatrixTrait
to imply that any generic type satisfying this trait would also satisfy the bounds. However, in the code above it seems necessary to explicitly write out the trait bound a second time in the generic function, otherwise the following error is given:
error[E0277]: the trait bound `<T as Index<(usize, usize)>>::Output: From<f64>` is not satisfied
--> src/main.rs:33:9
|
6 | trait MatrixTrait: IndexMut<(usize,usize)>
| ----------- required by a bound in this
7 | where
8 | <Self as Index<(usize,usize)>>::Output : From<f64>
| --------- required by this bound in `MatrixTrait`
...
33 | T : MatrixTrait,
| ^^^^^^^^^^^ the trait `From<f64>` is not implemented for `<T as Index<(usize, usize)>>::Output`
|
help: consider further restricting the associated type
|
33 | T : MatrixTrait, <T as Index<(usize, usize)>>::Output: From<f64>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Since my interpretation clearly seems to be off, how should one read bounds on trait definitions? Is there a way to achieve the goal of bounding implementors of the trait without having to repeat the bound in all users of types satisfying the trait? I.e. can this bound somehow live as part of the supertrait declaration, so that it is implied by T : MatrixTrait
?
Thanks!