I have been learning Rust, coming from a Swift, C and C++ background. I feel like I have a basic understanding of ownership, borrowing and traits. To exercise a bit, I decided to implement a sum
function on a generic slice [T]
where T
has a default value and can be added to itself.
This is how far I got:
trait Summable {
type Result;
fn sum(&self) -> Self::Result;
}
impl<T> Summable for [T]
where
T: Add<Output = T> + Default,
{
type Result = T;
fn sum(&self) -> T {
let x = T::default();
self.iter().fold(x, |a, b| a + b)
}
}
Compiler complains with expected type parameter T, found &T
for a + b
.
I understand why the error happens, but not exactly how to fix it. Yes, the type of x
is T
. It cannot be &T
because, if nothing else, if the slice is empty, that's the value that is returned and I cannot return a reference to something created inside the function. Plus, the default function returns a new value that the code inside the function owns. Makes sense. And yes, b
should be a shared reference to the values in the slice since I don't want to consume them (not T
) and I don't want to mutate them (not &mut T
).
But that means I need to add T
to &T
, and return a T
because I am returning a new value (the sum) which will be owned by the caller. How?
PS: Yes, I know this function exists already. This is a learning exercise.
The std::ops::Add
trait has an optional Rhs
type parameter that defaults to Self
:
pub trait Add<Rhs = Self> {
type Output;
fn add(self, rhs: Rhs) -> Self::Output;
}
Because you've omitted the Rhs
type parameter from the T: Add<Output = T>
bound, it defaults to T
: hence to your a
you can add a T
, but not an &T
.
Either specify that T: for<'a> Add<&'a T, Output = T>
; or else somehow obtain an owned T
from b
, e.g. via T: Copy
or T: Clone
.