Why the compiler asks me to use the arguments directly? [duplicate] - rust

This question already has answers here:
Is it possible to call a function in Rust by naming its arguments?
(5 answers)
Closed 23 days ago.
I am trying to implement a Pendulum in rust, while using my own vector structure. When I try to create a new Pendulum that uses the vector I created the compiler asks me to use the arguments directly. It works when I use position: vector::Vector::new(0.0, 0.0), but for me it should work when I try to use specifying the variable name and value.
I don't understand why I can't specify the arguments value.
fn main() {
println!("Hello, world!");
}
struct Pendulum {
origin: vector::Vector,
position: vector::Vector,
angle: f32,
angular_velocity: f32,
angular_acceleration: f32,
r: f32, // length of the pendulum
m: f32, // mass
g: f32, // gravity
}
impl Pendulum {
fn new(x: f32, y: f32, r: f32) -> Pendulum {
Pendulum {
origin: vector::Vector::new( x, y ),
position: vector::Vector::new(x: 0.0, y: 0.0),
angle: 1.0,
angular_velocity: 0.0,
angular_acceleration: 0.0,
r: r,
m: 1.0,
g: 1.5,
}
}
fn update() {}
fn draw() {}
}
mod vector {
pub struct Vector {
pub x: f32,
pub y: f32,
}
impl Vector {
pub fn new(x: f32, y: f32) -> Vector {
Vector { x, y }
}
pub fn add(&mut self, other: Vector) -> &Vector {
self.x += other.x;
self.y += other.y;
self
}
pub fn set(&mut self, x: f32, y: f32) {
self.x = x;
self.y = y;
}
}
}
The compiler returns me:
error: invalid `struct` delimiters or `fn` call arguments
src/main.rs:24:23
> |
24 | position: vector::Vector::new(x: 0.0, y: 0.0),
> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> |
help: if `vector::Vector::new` is a struct, use braces as delimiters
> |
24 | position: vector::Vector::new { x: 0.0, y: 0.0 },
> | ~ ~
help: if `vector::Vector::new` is a function, use the arguments directly
> |
24 - position: vector::Vector::new(x: 0.0, y: 0.0),
24 + position: vector::Vector::new(0.0, 0.0),
> |
error: could not compile `rust-pendulum` due to previous error

Rust does not support named arguments for function calls. So Vector::new(x: 0.0, y: 0.0) is simply invalid syntax. It must be Vector::new(0.0, 0.0).

Related

Is there any way to chain trait object methods?

I'm playing with rasterization and ray tracing, and my algorithm works on objects that can be rotated, translated, scaled, and converted to a bunch of triangles. I implement this by creating the IntoTriangle trait:
pub trait IntoTriangle {
fn triangulate(&self) -> Vec<Triangle>;
fn rotate(&mut self, x: f32, y: f32, z: f32);
fn scale(&mut self, x: f32, y: f32, z: f32);
fn translate(&mut self, x: f32, y: f32, z: f32);
}
And then in my program I transform the object before converting it into triangles:
let obj = MyObjectType::new(...);
obj.scale(7.0, 7.0, 7.0);
obj.rotate(0.0, 45.0, 0.0);
obj.translate(3.0, 0.0, -30.0);
let triangles = obj.triangulate();
This code has been working for a long time. But recently I was going through a piece of unrelated code from gtk-rs and noticed how they stack up such calls in a very nice way, which I really loved because the usage becomes so much clearer:
let triangles = MyObjectType::new(...)
.scale(7.0, 7.0, 7.0)
.rotate(0.0, 45.0, 0.0)
.translate(3.0, 0.0, -30.0)
.triangulate();
To achieve this I would need to change scale/rotate/translate functions to take mut self and return Self (this is inspired by the gtk-rs code: https://gtk-rs.org/gtk4-rs/stable/latest/docs/src/gtk4/auto/application_window.rs.html#428-431 ):
fn rotate(mut self, x: f32, y: f32, z: f32) -> Self {
self.rotation = [x, y, z];
self
}
But this is not object-safe and the compiler won't let me do this unless I move these functions out of the trait.
Is there any other way of achieving similar behaviour for trait objects? I'm at the point where I'm almost ready to move these methods out of the trait for the sake of retaining this gtk-inspired look and feel.
You could wrap everything in a builder over generic IntoTriangle objects:
struct Triangle {}
trait IntoTriangle {
fn triangulate(&self) -> Vec<Triangle>;
fn rotate(&mut self, x: f32, y: f32, z: f32);
fn scale(&mut self, x: f32, y: f32, z: f32);
fn translate(&mut self, x: f32, y: f32, z: f32);
}
#[derive(Default)]
struct Fake {}
impl IntoTriangle for Fake {
fn triangulate(&self) -> Vec<Triangle> {
vec![]
}
fn rotate(&mut self, x: f32, y: f32, z: f32) {}
fn scale(&mut self, x: f32, y: f32, z: f32) {}
fn translate(&mut self, x: f32, y: f32, z: f32) {}
}
struct TriangleBuilder<T> {
inner: T,
}
impl<T: IntoTriangle + Default> TriangleBuilder<T> {
pub fn new() -> Self {
Self {
inner: Default::default(),
}
}
pub fn build(self) -> Vec<Triangle> {
self.inner.triangulate()
}
pub fn rotate(mut self, x: f32, y: f32, z: f32) -> Self {
self.inner.rotate(x, y, z);
self
}
pub fn scale(mut self, x: f32, y: f32, z: f32) -> Self {
self.inner.scale(x, y, z);
self
}
pub fn translate(mut self, x: f32, y: f32, z: f32) -> Self {
self.inner.translate(x, y, z);
self
}
}
fn main() {
let triangles = TriangleBuilder::<Fake>::new()
.rotate(0f32, 0f32, 0f32)
.scale(1f32, 1f32, 1f32)
.translate(3f32, 4f32, 5f32)
.build();
}
Playground
Note that I use a Default bind for the implementation (for simplicity). But if needed you could have a constructor that takes the object itself or a reference if you needed.

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?

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

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.

Resources