How do I declare a generic function which can add together references to sparse vectors? [duplicate]

柔情痞子 提交于 2021-01-27 12:25:05

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!