expected struct `Vec3d`, found type parameter `u32` when implmenting the Mul trait for a custom struct - rust

I am trying to implement the Mul trait for the Vec3d struct. I want the mul function to multiply each element of Vec3d by a number and return a Vec3d. However I am getting faced with this error:
error[E0053]: method `mul` has an incompatible type for trait
--> src\vec_3d.rs:26:21
|
23 | impl<u32> Mul for Vec3d<u32> {
| --- this type parameter
...
26 | fn mul(self, t: u32) -> Self::Output {
| ^^^
| |
| expected struct `Vec3d`, found type parameter `u32`
| help: change the parameter type to match the trait: `Vec3d<u32>`
|
= note: expected fn pointer `fn(Vec3d<_>, Vec3d<u32>) -> Vec3d<_>`
found fn pointer `fn(Vec3d<_>, u32) -> Vec3d<_>`
My code looks like this:
use std::ops::Add;
use std::ops::Mul;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Vec3d<T> {
pub x: T,
pub y: T,
pub z: T,
}
impl<u32> Mul for Vec3d<u32> {
type Output = Self;
fn mul(self, t: u32) -> Self::Output {
Self {
x: self.x * t,
y: self.x * t,
z: self.x * t,
}
}
}
I had this originally with the generic type parameter T:
impl<T: Mul<Output = T>> Mul for Vec3d<T> {
type Output = Self;
fn mul(self, t: T) -> Self::Output {
Self {
x: self.x * t,
y: self.x * t,
z: self.x * t,
}
}
}
I have seen this be done the same way in some examples and other questions. What is wrong and how I can implement this the correct way?

This is nearly the same as the example on the Mul documentation: Multiplying vectors by scalars as in linear algebra
Mul has a default generic, which you can see in the trait definition:
pub trait Mul<Rhs = Self> {
This offers convenience since most implementers of Mul will be multiplying against Self. You aren't, so you need to specify the generic:
impl Mul<u32> for Vec3d<u32> {
type Output = Self;
fn mul(self, t: u32) -> Self::Output {
Self {
x: self.x * t,
y: self.y * t,
z: self.z * t,
}
}
}
To make this fully generic, you might try this:
impl<T: Mul<Output = T>> Mul<T> for Vec3d<T>
However, since you're using a single T 3 times, you would need to restrict it to Clone or Copy. The usual way to get around this is to implement Mul for references:
impl<'a, T> Mul<&'a T> for Vec3d<T>
where
T: Mul<&'a T, Output = T>,
{
type Output = Self;
fn mul(self, t: &'a T) -> Self::Output {
Self {
x: self.x * t,
y: self.y * t,
z: self.z * t,
}
}
}
Then you probably want a non-reference version for when the type implements Copy:
impl<T> Mul<T> for Vec3d<T>
where
T: Mul<Output = T> + Copy,
{
type Output = Self;
fn mul(self, t: T) -> Self::Output {
Self {
x: self.x * t,
y: self.y * t,
z: self.z * t,
}
}
}
But even better, you can do both of those in one impl:
impl<T, R> Mul<R> for Vec3d<T>
where
R: Copy,
T: Mul<R, Output = T>,
{
type Output = Self;
fn mul(self, t: R) -> Self::Output {
Self {
x: self.x * t,
y: self.y * t,
z: self.z * t,
}
}
}
When R is &T you cover the first impl, and when R is T and Copy you cover the second impl. & references are always Copy.
Another common thing to do is implement Mul for every integer type, which allows you more control over the implementation, for example if you wanted to optimize them for certain sized integers.

Related

How to implement Mul Trait for a custom struct type to work in both ways

// main.rs
#[derive(Clone, Copy)]
struct A(f64, f64);
impl<T> Mul<T> for A
where
f64: From<T>,
T: Copy, // f64: Mul<T>,
{
type Output = A;
fn mul(mut self, rhs: T) -> Self::Output {
self.0 = self.0 * f64::from(rhs);
self.1 = self.1 * f64::from(rhs);
self
}
}
impl Mul<A> for i32 {
type Output = A;
fn mul(self, mut rhs: A) -> Self::Output {
rhs.0 = rhs.0 * f64::from(self);
rhs.1 = rhs.1 * f64::from(self);
rhs
}
}
fn main() {
let mut a = A(1.0, 1.0);
a = a * 2; // is fine
a = a * 2.0; // is fine
a = a * 1 as u8; // is fine
a = 2 * a; // is fine because I did implement for i32 type
a = 2.0 * a; // impl this with generic type!
}
I'm able to implement Mul Trait for my struct A with generic parameter T ,
impl<T> Mul<T> for A
where
f64: From<T>,
T: Copy,
{
type Output = A;
fn mul(mut self, rhs: T) -> Self::Output {
self.0 = self.0 * f64::from(rhs);
self.1 = self.1 * f64::from(rhs);
self
}
}
Now I can multiply A with any numeric type like
A * f64 or A * i32 etc
But I am unable to implement Mul Trait with generic parameter which make me to do this:
f64 * A and i32 * A
Is there any way to implement it like this
impl Mul<A> for i32 {
type Output = A;
fn mul(self, mut rhs: A) -> Self::Output {
rhs.0 = rhs.0 * f64::from(self);
rhs.1 = rhs.1 * f64::from(self);
rhs
}
}
But for all types (generic parameter)
impl<T> Mul<A> for T { // error:type parameter `T` must be covered by another type when it appears before the first local type
type Output = A;
fn mul(self, mut rhs: A) -> Self::Output {
rhs.0 = rhs.0 * f64::from(self);
rhs.1 = rhs.1 * f64::from(self);
rhs
}
}
Complete error:
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`A`)
--> src\main.rs:64:6
|
64 | impl<T> Mul<A> for T {
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`A`)
|
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
For more information about this error, try `rustc --explain E0210`.
You can't. You can only be generic for the right-hand argument.
How libraries generally solve this is implement it generically for Self * T, and then make a macro that implements T* Self in terms of Self * T explicitly substituting T for the list of types they support, e.g. as in nalgebra:
left_scalar_mul_impl!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, f32, f64);

Require commutative operation in Rust trait bound

Suppose I have a group of related non-scalar structs with a commutative arithmetic operation defined on them. For example,
struct Foo {
a: f64,
b: f64
}
impl Add<f64> for Foo {
type Output = Foo;
fn add(self, v: f64) -> Self::Output {
Foo {
a: self.a + v,
b: self.b + v
}
}
}
impl Add<Foo> for f64 {
type Output = Foo;
fn add(self, foo: Foo) -> Self::Output {
Foo {
a: foo.a + self,
b: foo.b + self
}
}
}
I want to implement a trait on this group of structs, taking advantage of this operation. That is, I want something like the following:
trait Bar: Add<f64, Output = Self> + Sized {
fn right_add(self, f: f64) -> Self {
self + f
}
// Doesn't compile!
fn left_add(self, f: f64) -> Self {
f + self
}
}
However, this currently doesn't compile, since the super-trait bound doesn't include the left addition of f64 to Self. My question is: How can I state this commutative trait bound?
(Playground link.)
Edit: To be clear, I'm aware that right_add and left_add have the same output. I'm mainly interested in the ergonomics of not having to remember which is "correct" according to the compiler. In addition, I'm curious to learn how to do this, even if it's not strictly necessary.
Inverted trait bounds like this are the exact usecase for where syntax:
trait Bar
where
f64: Add<Self, Output = Self>,
Self: Add<f64, Output = Self> + Sized,
{
fn right_add(self, f: f64) -> Self {
self + f
}
fn left_add(self, f: f64) -> Self {
f + self
}
}
Playground link

Method not found using trait

I'm a beginner of Rust. I created an trait named Floating, f32 and f64 implement this trait. A generic struct Vec requiring that T must implement Floating trait. I would like to compute norm of the vector, this won't compile with the error message said that no method named sqrt found for type parameter T in the current scope. Why this is happening and how would it work?
use std::ops::{Mul, Add};
trait Floating: Sized + Copy + Clone + Mul<Output=Self> + Add<Output=Self> {}
impl Floating for f32 {}
impl Floating for f64 {}
struct Vec<T: Floating> {
x: T,
y: T,
z: T,
}
impl<T: Floating> Vec<T> {
fn norm(&self) -> T {
(self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
}
}
fn main() {
let v: Vec<f32> = Vec {x: 1.0, y: 1.0, z: 1.0};
println!("norm is {:?}", v.norm());
}
First of all, you probably shouldn't name your type Vec, to avoid conflicts and confusion with the std::vec::Vec container.
The issue is that (your) Vec only knows that T requires Floating, and Floating doesn't have a sqrt method. So you need to define that yourself.
trait Floating: Sized + Copy + Clone + Mul<Output = Self> + Add<Output = Self> {
fn sqrt(self) -> Self;
}
impl Floating for f32 {
fn sqrt(self) -> Self {
f32::sqrt(self)
}
}
impl Floating for f64 {
fn sqrt(self) -> Self {
f64::sqrt(self)
}
}
This is where the num crate comes in handy, as it defines a Float trait, which includes among others a sqrt() method. Using num you can simplify your example to:
// num = "0.3"
use num::Float;
struct Vec<T: Float> {
x: T,
y: T,
z: T,
}
impl<T: Float> Vec<T> {
fn norm(&self) -> T {
(self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
}
}
fn main() {
let v: Vec<f32> = Vec {
x: 1.0,
y: 1.0,
z: 1.0,
};
println!("norm is {:?}", v.norm());
}

Generic Implementation gets "cannot add 'T' to 'T' error

I'm trying to generic implementation and is trying to add a struct's fields of x and y which are both of type T,
I'm getting a red squiggly line under impl<T> Point<T> and also the following error message...
cannot add `T` to `T`
no implementation for `T + T`
help: the trait `std::ops::Add` is not implemented for `T`
As can be seen from my code, I have already added the trait std::ops::Add for type T.
How do I get the code below working?
struct Point<T>
where
T: std::ops::Add<Output = T>,
{
x: T,
y: T,
}
impl Point<f32> {
fn add_f32(&self) -> f32 {
self.x + self.y
}
}
//error
impl<T> Point<T> {
fn add(&self) -> T
where
T: std::ops::Add<Output = T>,
{
self.x + self.y
}
}
There are two solutions to this problem, which have different pros and cons.
The first solution is to just remove the T: std::ops::Add<Output = T> bound from the struct definition:
struct Point<T> {
x: T,
y: T,
}
This means that the add() method is unavailable for a type Point<T>, if T doesn't implement Add. However, you're still able to create such a type. If you then try to call the add() method on it, Rust will show an error – playground link.
The other solution is to keep the trait bound, which means that it must be enforced every time it is used:
struct Point<T: Add<Output = T>> {
x: T,
y: T,
}
impl<T: Add<Output = T>> Point<T> {
// ^^^^^^^^^^^^^^^ required
...
}
This means that a Point<T> can only exist if T implements Add. You can do this if a type Point<SomeTypeThatIsntAdd> doesn't make sense at all or is useless. It also improves compiler diagnostics in some cases.
struct Point<T> {
x: T,
y: T,
}
impl Point<f32> {
fn add_f32(&self) -> f32 {
self.x + self.y
}
}
impl<T> Point<T> {
fn add(self) -> T
where
T: std::ops::Add<Output = T>,
{
self.x + self.y
}
}

Method `mul` has an incompatible type for trait

I'm creating a simple matrix struct in Rust and I'm trying to implement some basic operator methods:
use std::ops::Mul;
struct Matrix {
cols: i32,
rows: i32,
data: Vec<f32>,
}
impl Matrix {
fn new(cols: i32, rows: i32, data: Vec<f32>) -> Matrix {
Matrix {
cols: cols,
rows: rows,
data: data,
}
}
}
impl Mul<f32> for Matrix {
type Output = Matrix;
fn mul(&self, m: f32) -> Matrix {
let mut new_data = Vec::with_capacity(self.cols * self.rows);
for i in 0..self.cols * self.rows {
new_data[i] = self.data[i] * m;
}
return Matrix {
cols: *self.cols,
rows: *self.rows,
data: new_data,
};
}
}
fn main() {}
I'm still familiarizing myself with Rust and systems programming and I'm sure the error is pretty obvious. The compiler tells me:
error[E0053]: method `mul` has an incompatible type for trait
--> src/main.rs:22:5
|
22 | fn mul(&self, m: f32) -> Matrix {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Matrix`, found &Matrix
|
= note: expected type `fn(Matrix, f32) -> Matrix`
found type `fn(&Matrix, f32) -> Matrix`
It's referring to the contents of the for loop (I believe). I've tried playing around with a few other things but I can't get my head around it.
The error message is spot-on here:
error[E0053]: method `mul` has an incompatible type for trait
--> src/main.rs:22:5
|
22 | fn mul(&self, m: f32) -> Matrix {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Matrix`, found &Matrix
|
= note: expected type `fn(Matrix, f32) -> Matrix`
found type `fn(&Matrix, f32) -> Matrix`
Let's look at the Mul trait to see why your implementation doesn't match:
pub trait Mul<RHS = Self> {
type Output;
fn mul(self, rhs: RHS) -> Self::Output;
}
This says that unless you specify anything further, RHS will be the same type as Self. Self is the type that the trait will be implemented on. Let's look at your definition:
impl Mul<f32> for Matrix {
type Output = Matrix;
fn mul(&self, m: f32) -> Matrix {}
}
In your case, you have substituted f32 for RHS, and Matrix for Output. Also, Matrix is the implementing type. Let's take the trait definition and substitute in, producing some pseudo-Rust:
pub trait Mul {
fn mul(self, rhs: f32) -> Matrix;
}
Now do you see what is different?
// Trait
fn mul(self, m: f32) -> Matrix;
// Your implementation
fn mul(&self, m: f32) -> Matrix;
You have incorrectly specified that you take &self instead of self.
For completeness, here's the implementation. I threw in style fixes at no charge!
impl Mul<f32> for Matrix {
type Output = Matrix;
fn mul(self, m: f32) -> Matrix {
let new_data = self.data.into_iter().map(|v| v * m).collect();
Matrix {
cols: self.cols,
rows: self.rows,
data: new_data,
}
}
}
This is a bit inefficient as it deallocates and reallocates the data vector. Since you are taking the Matrix by value, we can just edit it in place:
impl Mul<f32> for Matrix {
type Output = Matrix;
fn mul(mut self, m: f32) -> Matrix {
for v in &mut self.data {
*v *= m
}
self
}
}

Resources