问题
I'm trying to use the sprs crate (version 0.6.3
) to manipulate sparse vectors. I'd like to add two vectors together.
I started off with an implementation of the Add
trait, then simplified this to an implementation function. Finally, I've boiled down the problem to a simple generic function.
// This works: the scalar type `u64` is fixed here
fn adder(first: &CsVec<u64>, second: &CsVec<u64>) -> CsVec<u64> {
first + second
}
// When I try to make the scalar type generic, it doesn't work
fn adder2<T>(first: &CsVec<T>, second: &CsVec<T>) -> CsVec<T>
where
CsVec<T>: Add,
T: Add + Debug,
{
first + second
}
The first version compiles fine, but I'd like to know why the second version won't compile. I get this error message:
error[E0369]: binary operation `+` cannot be applied to type `&sprs::sparse::CsVecBase<std::vec::Vec<usize>, std::vec::Vec<T>>`
--> libp3prime/src/lib/datacache.rs:62:5
|
62 | first + second
| ^^^^^^^^^^^^^^
|
= note: an implementation of `std::ops::Add` might be missing for `&sprs::sparse::CsVecBase<std::vec::Vec<usize>, std::vec::Vec<T>>`
I don't really understand the error message. I know that you can add two CsVecs
together, since adder()
compiles, so I am a bit lost.
The two vectors should add together.
回答1:
Be sure that the trait bounds defined on the function match the behavior used in the function.
first
and second
are not CsVec<T>
, but &CsVec<T>
. In Rust, &X
is a different type from X
. You need a trait bound that says that you can add two &CsVec<T>
s and get a CsVec<T>
as output:
fn adder2<'a, T>(first: &'a CsVec<T>, second: &'a CsVec<T>) -> CsVec<T>
where
&'a CsVec<T>: Add<Output = CsVec<T>>,
{
first + second
}
No bounds on T
are needed in this example.
The 'a
lifetime parameter in this case was passed in to the function. Sometimes it is useful to define a trait bound on a reference inside the function, for example, to use +
on references to local variables. In that case you would want to use the higher-ranked trait bound for<'a> &'a CsVec<T>: Add<Output = CsVec<T>>
instead. See the linked questions below for more information.
Lukas Kalbertodt points out that it may sometimes be more flexible to say "I just want to add two &CsVec<T>
s, and I will return whatever type that operation gives me", which you can do by returning <&'a CsVec<T> as Add>::Output
:
fn adder2<'a, T>(first: &'a CsVec<T>, second: &'a CsVec<T>) -> <&'a CsVec<T> as Add>::Output
where
&'a CsVec<T>: Add,
{
first + second
}
In this case the output type does not have to be exactly CsVec<T>
, but when it is, it works the same way as the first version.
Related
- How to write a trait bound for adding two references of a generic type?
- How do I require a generic type implement an operation like Add, Sub, Mul, or Div in a generic function?
来源:https://stackoverflow.com/questions/54710817/how-do-i-declare-a-generic-function-which-can-add-together-references-to-sparse