Generic type with internal Mul

i have applied trait for multiplication, but it gave me error can someone
give me solution for get_square and why after println macro value can still borrowed.

use std::ops::Mul;

#[derive(Debug)]
struct Point<T, U> { x: T, y: U }

impl<T: Mul, U: Mul> Point<T, U> {

    pub fn get_hrzntl(&self) -> &T { &self.x }

    pub fn get_vertical(&self) -> &U { &self.y }

    pub fn get_square<V> (&self) -> V { &self.x * &self.y }

}


fn main() {
    let rect = Point{ x: 10, y: 20.5 };

    println!("Create Example Point {{x: 10, y: 20.5}}");

    println!("Rectangle  value : {:?}", rect);
    println!("Horizontal value : {}", rect.get_hrzntl());  // value can still borowed here?
    println!("Vertical   value : {}", rect.get_vertical());
    println!("Square     value : {}", rect.get_square());
}

error[E0369]: cannot multiply &U to &T
--> src/main.rs:12:49
|
12 | pub fn get_square (&self) -> V { &self.x * &self.y }
| ------- ^ ------- &U
| |
| &T
|
help: consider further restricting this bound
|
6 | impl<T: Mul + std::ops::Mul<Output = &U>, U: Mul> Point<T, U> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0282]: type annotations needed
--> src/main.rs:25:44
|
25 | println!("Square value : {}", rect.get_square());
| ^^^^^^^^^^ cannot infer type for type parameter V declared on the associated function get_square
|
help: consider specifying the type argument in the method call
|
25 | println!("Square value : {}", rect.get_square::());
| ^^^^^

error: aborting due to 2 previous errors

I'm sorry, if it's an miss understanding of generic types, rust doesn't allow different generic types to perform math operations it can lean to bug or security issue, thx to rust community for detailed doc.

my personal opinion, rust is great language aware of this generic patern.
T and U is different on generic

use std::ops::Mul;

trait Operation<T, U> {
    fn trait_square_x(&self) -> T;
    fn trait_square_y(&self) -> U;
}

#[derive(Debug)]
struct Point<T, U> { x: T, y: U }

impl<T: Mul<Output= T> + Clone, U: Mul<Output= T> + Clone> Point<T, U> {

    pub fn get_hrzntl(&self) -> &T { &self.x }

    pub fn get_vrtcl(&self) -> &U { &self.y }

    pub fn get_square_x (&self) -> T { self.x.clone() * self.x.clone() }

    pub fn get_square_y (&self) -> T { self.y.clone() * self.y.clone() }

}

impl<T: Mul<Output = T> + Clone, U: Mul<Output = U> + Clone > Operation<T, U> for Point<T, U> {

    fn trait_square_x(&self) -> T { self.x.clone() * self.x.clone() }

    fn trait_square_y(&self) -> U { self.y.clone() * self.y.clone() }

}


fn main() {
    let rect = Point{ x: 10, y: 20 };

    println!("Create Example Point {{x: 10, y: 20}}");

    println!("Rectangle       value : {:?}", rect);
    println!("Horizontal      value : {}", rect.get_hrzntl());
    println!("Vertical        value : {}", rect.get_vrtcl());
    println!("Square x        value : {}", rect.get_square_x());
    println!("Square y        value : {}", rect.get_square_y());
    println!("trait Square x  value : {}", rect.trait_square_x());
    println!("trait Square y  value : {}", rect.trait_square_y());

}

Your original code can be made to (mostly) work, but the bounds start to get a bit unwieldy:

    pub fn get_square<'a, V>(&'a self) -> V
    where
        &'a T: Mul<&'a U, Output = V>,
    {
        &self.x * &self.y
    }

(Playground)

1 Like
  • T: Mul is shorthand for T: Mul<T, Output = T>, meaning an instance of T can be multiplied with another instance of T and the output is an instance of T. Same for U: Mul. However you're trying to multiply an &T with an &U, so the bound should be something like &T: Mul<&U> (actually for<'a> &'a T: Mul<&'a U> because you need to use explicit lifetimes). With this bound the output type will be <&'a T as Mul<&'a U>>::Output for some lifetime 'a you need to define on the function where it's used or just <&T as Mul<&U>>::Output if the lifetime can be inferred.

  • In pub fn get_square<V> (&self) -> V { &self.x * &self.y } that <V> allows the caller to decide what will the output type be, which in this case is never possible. Remove that <V> from the function definition and change the output type to <&T as Mul<&U>>::Output

  • In your main you create a Point with an integer and a float, however there's no implementation for multiplying an integer and a float, even normally you need to cast one of them before (example)

Fixed code

As for why rect can be used after the first println!, that's because println! doesn't consume its input, but just borrows them. This works because it's a macro, if it were a function it would have consumed it or you would had to put an & before rect.

2 Likes

let me try first.

error[E0277]: cannot multiply &{float} to &{integer}
--> src/main.rs:28:44
|
28 | println!("Square value : {}", rect.get_square());
| ^^^^^^^^^^ no implementation for &{integer} * &{float}
|
= help: the trait Mul<&{float}> is not implemented for &{integer}

yes it works @SkiFire13 your example more clear to me.

your code differ from my code.

this same type : i32
let rect = Point { x: 10, y: 20 };
when it use same T why im using Point<T, U>
just use Point

my code was
let rect = Point {x: 10, y: 20.5 }
when i change to my, then landing on problem.

The impl block has the bound for<'a> &'a T: Mul<&'a U>, which means the functions inside are only available for those Points for which the bound holds (i.e., when &T can be multiplied with &U). The Point you've constructed does not fulfill the condition: Rust's standard library has not implemented multiplication for &integer * &float.

fn main() {
    let i = 10;
    let f = 20.5;
    let result = &i * &f;
}
error[E0277]: cannot multiply `&{float}` to `&{integer}`
 --> src\main.rs:4:21
  |
4 |     let result = &i * &f;
  |                     ^ no implementation for `&{integer} * &{float}`
  |
  = help: the trait `std::ops::Mul<&{float}>` is not implemented for `&{integer}`       

The &{integer} and &{float} are just placeholders because the compiler isn't sure what integer or float types they are supposed to be, the error below which uses concrete types might be more clear:

fn main() {
    let i: i32 = 10;
    let f: f32 = 20.5;
    let result = i * f;
}
error[E0277]: cannot multiply `f32` to `i32`
 --> src\main.rs:4:20
  |
4 |     let result = i * f;
  |                    ^ no implementation for `i32 * f32`
  |
  = help: the trait `std::ops::Mul<f32>` is not implemented for `i32`
1 Like

That's why I said:

I should've probably been more clear on that. Also probably you would prefer to change that 10 into a float instead of what I did. Writing let rect = Point {x: 10.0, y: 20.5 }; should work

Yes multiplication integer to float, thanks mr @Heliozoa