In my understanding, when I have this constraint: for<'a> Self::FirstStepOutput<'a>: AsRef<[N]> in the implementation of TwoStepsCalc for CalcVec, because FirstStepOutput is a AsRef<[f32]>, so the compiler should know that N is f32. But it seems not. What am I doing wrong?
AsRef could be implemented with many different slice types for any given type. In Vec's case it's true that as things currently stand it wouldn't be possible to add an implementation that didn't violate the coherence rules, but the compiler doesn't use the coherence rules to prove that a type parameter must be equivalent to a concrete type like that.
It's hard to say what the best fix is here without more context, but one option is to move N to be a type parameter on the trait instead. Then you can either only implement the trait with f32, or specify the additional bounds that allow you to work with N.
It would be a non-semver-breaking change for the standard library to add
impl AsRef<[()]> for Vec<f32>
(One of the balancing acts of coherence and generics is to give both upstream and downstream enough flexibility to make changes without breaking everything.)
More generally speaking, if you need a type parameter like N to have any particular capabilities in your function body, they have to be expressed as trait bounds.
You can't do it without deeper changes. For calc_first_step to make sense, you need
impl<'y> TwoStepsCalc<&'y Vec<f32>> for CalcVecVec {
type FirstStepOutput<'x> = Vec<&'x Vec<f32>>;
type SecondStepEleOutput = f32;
fn calc_first_step<'a>(&self, data_save: &'a DataSave) -> Self::FirstStepOutput<'a> {
vec![&data_save.vec_f32, &data_save.vec_f32]
}
fn calc_second_step<T>(&self, data: T) -> Vec<Self::SecondStepEleOutput>
where
T: AsRef<[&'y Vec<f32>]>,
for<'a> Self::FirstStepOutput<'a>: AsRef<[&'y Vec<f32>]>,
{
let data_as_ref = data.as_ref();
data_as_ref[0].iter().zip(data_as_ref[1].iter()).map(|(x, y)| x + y).collect()
}
}
That compiles, but the higher-ranked trait bound on calc_second_step isn't actually tested until you try to use it, and then it fails because Vec<&'x T> implements AsRef<[&'x T]> not AsRef<[&'some_other_lifetime T]>.
Thanks very much. It works exactly as what I am needing.
I made the following tests:
when type A = Vec<f32>, parameter data can be &Vec<f32>, Vec<f32>, &[f32]
when type A = Vec<&[f32]>, parameter data can be Vec<&[f32]>, &Vec<&[f32]>,
when type A = Vec<&Vec<f32>>, parameter data can be Vec<&Vec<f32>>, &Vec<&Vec<f32>>,
The limits is :
when type A = Vec<&[f32]>, data can not be Vec<&Vec<f32>>,
when type A = Vec<&Vec<f32>>, data can not be Vec<&[f32]>.
I think it is because that one type implemented on AsRef<[&Vec<f32>]>, the compiler can not make sure it also implemented on As<[&[f32]]>. But one type that is Vec<f32>, the compiler can make sure it is also a &[f32].