Rust uses a design pattern called extension traits. They work in a similar manner like above class extensions, but are required to be explicitly used. This makes it easier to trace back where a particular method is coming from.
When I tried it at the playground I got the below error:
Compiling playground v0.0.1 (/playground)
error[E0603]: trait `SquareExt` is private
--> src/main.rs:12:9
|
12 | use foo::SquareExt;
| ^^^^^^^^^^^^^^
warning: unused import: `foo::SquareExt`
--> src/main.rs:12:9
|
12 | use foo::SquareExt;
| ^^^^^^^^^^^^^^
|
= note: #[warn(unused_imports)] on by default
error[E0689]: can't call method `square` on ambiguous numeric type `{integer}`
--> src/main.rs:13:22
|
13 | println!("{}", 5.square());
| ^^^^^^
help: you must specify a concrete type for this numeric value, like `i32`
|
13 | println!("{}", 5_i32.square());
| ^^^^^
error: aborting due to 2 previous errors
Some errors occurred: E0603, E0689.
For more information about an error, try `rustc --explain E0603`.
error: Could not compile `playground`.
To learn more, run the command again with --verbose.
Which had been modified to handle another parameter as below:
trait SquareExt {
fn square(self, i32) -> Self;
// fn square(self, _: i32) -> Self; // in Rust 2018, name is a must even if it is just _
}
impl SquareExt for i32 {
fn square(self, i: i32) -> Self { self * i }
}
fn main() {
println!("{}", 5.square(2)); // prints 10
}
Thanks.
How can I implement it for generat type T, I tried:
use std::ops::Mul;
impl<T: Mul> SquareExt
for T
where T: Mul
{
fn square(self) -> Self { self * self }
}
but got the below error:
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
--> src/main.rs:11:35
|
11 | fn square(self) -> Self { self * self }
| ---- ^^^^^^^^^^^ expected type parameter, found associated type
| |
| expected `T` because of return type
|
= note: expected type `T`
found type `<T as std::ops::Mul>::Output`
Thankig to this, I found the solution required using <Output = T> because of the return type, and require using copy if self is used more than one, as it will be moved after the first usage, so the final solution I've is:
mod foo {
pub trait SquareExt {
fn square(self) -> Self;
}
use std::ops::Mul;
impl<T> SquareExt
for T
where T: Mul<Output = T> + Copy
{
fn square(self) -> T { self * self }
}
}
fn main() {
use foo::SquareExt;
// or with Rust 2018
// use self::foo::SquareExt;
println!("{}", 5.1.square()); // prints 26.009999999999998
}
Note that you don't have to require T: Mul<Output = T>. You can just allow square() to return the same type Mul returns:
mod foo {
pub trait SquareExt {
type Output;
fn square(self) -> Self::Output;
}
use std::ops::Mul;
impl<T> SquareExt for T
where
T: Mul + Copy,
{
type Output = <T as Mul>::Output;
fn square(self) -> Self::Output {
self * self
}
}
}