Method not found using trait - rust

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());
}

Related

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

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.

Could Rust take an immutable reference of a value automatically?

I have a struct with a couple of operators implemented for it:
use std::ops;
/// Vector of 3 floats
#[derive(Debug, Copy, Clone)]
pub struct Vec3 {
pub x: f32,
pub y: f32,
pub z: f32,
}
/// Add operator
impl ops::Add<&Vec3> for &Vec3 {
type Output = Vec3;
#[inline(always)]
fn add(self, rhs: &Vec3) -> Self::Output {
Vec3 {
x: self.x + rhs.x,
y: self.y + rhs.y,
z: self.z + rhs.z,
}
}
}
/// Subtract operator
impl ops::Sub<&Vec3> for &Vec3 {
type Output = Vec3;
#[inline(always)]
fn sub(self, rhs: &Vec3) -> Self::Output {
Vec3 {
x: self.x - rhs.x,
y: self.y - rhs.y,
z: self.z - rhs.z,
}
}
}
/// Scalar multiplication operator
impl ops::Mul<&Vec3> for f32 {
type Output = Vec3;
#[inline(always)]
fn mul(self, rhs: &Vec3) -> Self::Output {
Vec3 {
x: self * rhs.x,
y: self * rhs.y,
z: self * rhs.z,
}
}
}
I want to use the operators:
let a = Vec3 { x: 0.0, y: 0.5, z: 1.0 };
let b = Vec3 { x: 1.0, y: 0.5, z: 0.0 };
let c = Vec3 { x: 1.0, y: 1.0, z: 0.0 };
let d = Vec3 { x: 0.0, y: 1.0, z: 1.0 };
let result = 2.0 * (a + b) - 3.0 * (c - d);
This code will not compile because the operators are implemented for &Vec3, not for Vec3. To fix the issue, the last line would have to look like this:
let result = &(2.0 * &(&a + &b)) - &(3.0 * &(&c - &d));
Which doesn't look that nice anymore.
I understand that I could implement the operators for Vec3 to avoid that problem, but what if I still want to use immutable references to these vectors on the stack? Is there perhaps a way to give Rust some hint that if I write a + b and there is no operator for Vec3 + Vec3, that it could try and look for a &Vec3 + &Vec3 operator instead, and if found, take the immutable references for both arguments automatically?
No, there is no way of automatically taking a reference when adding two values.
You could write your own macro that does this, I suppose. In usage, it would look like:
thing!{ a + b }
// expands to
(&a + &b)
I'd expect that this macro would quickly become tiresome to write.
See also:
Allow autoderef and autoref in operators — RFC #2147
Tracking issue: Allow autoderef and autoref in operators (experiment) #44762
Does println! borrow or own the variable?
How to implement idiomatic operator overloading for values and references in Rust?
Operator overloading by value results in use of moved value
How can I implement an operator like Add for a reference type so that I can add more than two values at once?

How can I use enum in a trait and implement trait on structs that are in the enum? Rust

I'm learning Rust so this might be a duplicate, since I'm still not sure how to search this. I tried to make a enum that contains different structs and since those structs have same methods but different implementation, I can't figure out how to properly write the types for the trait and the implementation. This is what I have so far:
struct Vector2 {
x: f32,
y: f32,
}
struct Vector3 {
x: f32,
y: f32,
z: f32,
}
enum Vector {
Vector2(Vector2),
Vector3(Vector3),
}
trait VectorAdd {
fn add(&self, other: &Vector) -> Vector;
}
impl VectorAdd for Vector2 {
fn add(&self, other: &Vector2) -> Vector2 {
Vector2 {
x: self.x + other.x,
y: self.y + other.y
}
}
}
This code does not compile, and the error messages don't make it clearer for me. Anyone can guide me how to write this properly? or if it's even possible?
Since you are using generics here, you don't need the enum to write the trait:
struct Vector2 {
x: f32,
y: f32,
}
struct Vector3 {
x: f32,
y: f32,
z: f32,
}
trait VectorAdd {
fn add(&self, other: &Self) -> Self;
}
impl VectorAdd for Vector2 {
fn add(&self, other: &Vector2) -> Vector2 {
Vector2 {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
impl VectorAdd for Vector3 {
fn add(&self, other: &Vector3) -> Vector3 {
Vector3 {
x: self.x + other.x,
y: self.y + other.y,
z: self.z + other.z,
}
}
}
(playground)
You can implement the enum based on this definition:
enum Vector {
Vector2(Vector2),
Vector3(Vector3),
}
impl VectorAdd for Vector {
fn add(&self, other: &Vector) -> Vector {
match (self, other) {
(Self::Vector2(a), Self::Vector2(b)) => Self::Vector2(a.add(b)),
(Self::Vector3(a), Self::Vector3(b)) => Self::Vector3(a.add(b)),
_ => panic!("invalid operands to Vector::add"),
}
}
}
Macros may help you if the number of variants gets large.

How to implement ops::Mul on a struct so it works with numerical types as well as another struct?

I have implemented a Point3D struct:
use std::ops;
#[derive(Debug, PartialEq)]
pub struct Point3D {
pub x: f32,
pub y: f32,
pub z: f32,
}
impl ops::Add<&Point3D> for &Point3D {
type Output = Point3D;
fn add(self, rhs: &Point3D) -> Point3D {
Point3D {
x: self.x + rhs.x,
y: self.y + rhs.y,
z: self.z + rhs.z,
}
}
}
impl ops::Sub<&Point3D> for &Point3D {
type Output = Point3D;
fn sub(self, rhs: &Point3D) -> Point3D {
Point3D {
x: self.x - rhs.x,
y: self.y - rhs.y,
z: self.z - rhs.z,
}
}
}
impl ops::Mul<&Point3D> for &Point3D {
type Output = f32;
fn mul(self, rhs: &Point3D) -> f32 {
self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
}
}
//Scalar impl of ops::Mul here
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn addition_point_3D() {
let point1 = Point3D {
x: 1.0,
y: 2.0,
z: 3.0,
};
let point2 = Point3D {
x: 4.0,
y: 5.0,
z: 6.0,
};
let result = &point1 + &point2;
assert_eq!(
result,
Point3D {
x: 5.0,
y: 7.0,
z: 9.0
},
"Testing Addition with {:?} and {:?}",
point1,
point2
);
}
#[test]
fn subtraction_point_3D() {
let point1 = Point3D {
x: 1.0,
y: 2.0,
z: 3.0,
};
let point2 = Point3D {
x: 4.0,
y: 5.0,
z: 6.0,
};
let result = &point1 - &point2;
assert_eq!(
result,
Point3D {
x: -3.0,
y: -3.0,
z: -3.0
},
"Testing Subtraction with {:?} and {:?}",
point1,
point2
);
}
#[test]
fn point3D_point3D_multiplication() {
let point1 = Point3D {
x: 1.0,
y: 2.0,
z: 3.0,
};
let point2 = Point3D {
x: 4.0,
y: 5.0,
z: 6.0,
};
let result = &point1 * &point2;
assert_eq!(
result, 32.0,
"Testing Multiplication with {:?} and {:?}",
point1, point2
);
}
/*
#[test]
fn point3D_scalar_multiplication() {
let point1 = Point3D { x: 1.0, y: 2.0, z: 3.0};
let scalar = 3.5;
let result = &point1 * &scalar;
assert_eq!(result, Point3D { x: 3.5, y: 7.0, z: 10.5 }, "Testing Multiplication with {:?} and {:?}", point1, scalar);
}
*/
}
I would like to use generics in my multiplication trait so that if I pass it another Point3D class it will implement the dot product, but if I pass it a basic numeric type (integer, f32, unsigned integer, f64) it will multiply x, y, and z by the scalar value. How would would I do this?
Do you mean something like that?
impl ops::Mul<f32> for &Point3D {
type Output = Point3D;
fn mul(self, rhs: f32) -> Point3D {
Point3D {
x: self.x * rhs,
y: self.y * rhs,
z: self.z * rhs
}
}
}
This would allow you to do the following:
let point = Point3D { x: 1.0, y: 2.0, z: 3.0};
let result = &point * 4.0;
To do this with generics you first need to make your Point3D struct accept generics, like
use std::ops::{Mul, Add};
#[derive(Debug, PartialEq)]
pub struct Point3D<T> {
pub x: T,
pub y: T,
pub z: T,
}
And your implementation of multiplication of Point3D with a numeric type would be
impl<T> Mul<T> for &Point3D<T>
where T: Mul<Output=T> + Copy
{
type Output = Point3D<T>;
fn mul(self, rhs: T) -> Self::Output {
Point3D {
x: self.x * rhs,
y: self.y * rhs,
z: self.z * rhs,
}
}
}
We have the where clause because our generic T would need to implement the traits Mul and Copy as well. Copy because we need to copy rhs to use in all the three multiplications.
Your dot product implementation would also need to change according to
impl<T> Mul<&Point3D<T>> for &Point3D<T>
where T: Mul<Output=T> + Add<Output=T> + Copy
{
type Output = T;
fn mul(self, rhs: &Point3D<T>) -> Self::Output {
self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
}
}
with the Add because we of course need to be able to add the generics T here.

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
}
}

Resources