Multiply trait implementations in Rust - rust

I'm trying to implement trait IDimTransformer for different generic types of traits IDimOffset0Transformer and IDimOffset1Transformer but compiler give me error
trait IDimTransformer {
fn get_offset_x(&self, x: i32) -> i32;
fn get_offset_z(&self, z: i32) -> i32;
}
trait IDimOffset0Transformer : IDimTransformer {}
trait IDimOffset1Transformer : IDimTransformer {}
impl<T: IDimOffset0Transformer> IDimTransformer for T {
fn get_offset_x(&self, x: i32) -> i32 {
return x;
}
fn get_offset_z(&self, z: i32) -> i32 {
return z;
}
}
impl<T: IDimOffset1Transformer> IDimTransformer for T {
fn get_offset_x(&self, x: i32) -> i32 {
return x - 1;
}
fn get_offset_z(&self, z: i32) -> i32 {
return z - 1;
}
}
Example of use
struct Layer {}
impl IDimOffset1Transformer for Layer{}
fn some_func(dim: &impl IDimTransformer, x: i32, z: i32) -> i32 {
return dim.get_offset_x(x) + dim.get_offset_z(x);
}
fn some_func_1(layer: &Layer, x: i32, z: i32) -> i32 {
return some_func(layer, x, z);
}
Compiler error
error[E0119]: conflicting implementations of trait `layer::IDimTransformer`:
--> src/layer.rs:59:1
|
49 | impl<T: IDimOffset0Transformer> IDimTransformer for T {
| ----------------------------------------------------- first implementation here
...
59 | impl<T: IDimOffset1Transformer> IDimTransformer for T {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation

I think the pattern you are looking for looks like this in rust:
trait Transformer {
fn get_offset_x(x: i32) -> i32;
fn get_offset_z(z: i32) -> i32;
}
struct Offset0Transformer;
impl Transformer for Offset0Transformer {
fn get_offset_x(x: i32) -> i32 {
x
}
fn get_offset_z(z: i32) -> i32 {
z
}
}
struct Offset1Transformer;
impl Transformer for Offset1Transformer {
fn get_offset_x(x: i32) -> i32 {
x - 1
}
fn get_offset_z(z: i32) -> i32 {
z - 1
}
}
struct Layer { x: i32, z: i32 };
impl Layer {
fn add_transformed<T: Transformer>(&self) -> i32 {
T::get_offset_x(self.x) + T::get_offset_z(self.z)
}
}
fn main() {
let layer = Layer { x: 5, z: 2 };
let result = layer.add_transformed::<Offset1Transformer>();
println!("got: {}", result);
}
Most of the time you won't need this though. Thinking through what your code is trying to do and thinking of a simpler way usually gets you smaller better code.

Related

Return only an owned type from a trait method that can accept an owned or borrowed value as input

I want to have a trait that can be implemented for T and &T but has methods that always return T.
What I would like to do is something like this
use std::borrow::ToOwned;
trait Foo<X: ToOwned> {
fn f(&self, x: X) -> f64;
fn g(&self) -> X::Owned;
}
struct Float(f64);
impl Foo<f64> for Float {
fn f(&self, x: f64) -> f64 {
x + self.0
}
fn g(&self) -> f64 {
self.0 * 2.0
}
}
struct List(Vec<f64>);
impl Foo<&Vec<f64>> for List {
fn f(&self, x: &Vec<f64>) -> f64 {
x.iter().sum()
}
// Error here - `&Vec<f64>` return type expected
fn g(&self) -> Vec<f64> {
self.0.iter().map(|&x| 2.0 * x).collect()
}
}
fn main() {
let float = Float(2.0);
println!("{} {}", float.f(3.0), float.g());
let list = List(vec![0.0, 1.0, 2.0]);
println!("{} {:?}", list.f(&vec![1.0, 2.0]), list.g());
}
I know that one option is to have a trait that defines the output type like so
trait FooReturn {
type Output;
}
trait Foo<X: FooReturn> {
fn f(&self, x: X) -> f64;
fn g(&self) -> X::Output;
}
then implement the trait for all relevant types, but I was wondering if there was a more standard/robust way to do this.
This is how you would do it once specialization is complete. Meanwhile, I couldn't even get a simple working example to compile on 1.55.0-nightly.
#![feature(specialization)]
trait MaybeOwned {
type Owned;
}
default impl<X> MaybeOwned for X {
type Owned = X;
}
impl<'a, X> MaybeOwned for &'a X {
type Owned = X;
}
trait Foo<X: MaybeOwned> {
fn f(&self, x: &X) -> f64;
fn g(&self) -> <X as MaybeOwned>::Owned;
}

How to impl conversion between different inner types?

This yields E0119:
#![feature(destructuring_assignment)]
pub struct Point<T> {
pub x: T,
pub y: T,
}
impl<F, T: From<F>> From<Point<F>> for Point<T> {
fn from<F>(f: Point<F>) -> Self {
let Point { mut x, mut y } = f;
(x, y) = (T::from(x), T::from(y));
Self { x, y }
}
}
The implementation conflict is in std::convert::From for T:
impl<T> From<T> for T {
fn from(t: T) -> T {
t
}
}
I assume there isn't a way to work around this so much as there may be more rust-idiomatic approach to the problem of converting between inner types, or even a more idiomatic understanding of what the "problem" is.
You can implement it as a normal method that takes a closure and then pass it the From::from trait method when you call it. Or even specialize it for types that implement From<T>:
#[derive(Debug)]
pub struct Point<T> {
pub x: T,
pub y: T,
}
impl<T> Point<T> {
pub fn map<U>(self, mut f: impl FnMut(T) -> U) -> Point<U> {
let Point { x, y } = self;
Point {
x: f(x),
y: f(y),
}
}
pub fn map_into<U: From<T>>(self) -> Point<U> {
let Point { x, y } = self;
Point {
x: U::from(x),
y: U::from(y),
}
}
}
fn main() {
let point_i16 = Point { x: 6i16, y: 3200i16 };
let point_f32: Point<f32> = point_i16.map(From::from);
let point_f64: Point<f64> = point_f32.map_into();
println!("{:?}", point_f64); // Point { x: 6.0, y: 3200.0 }
}

Using Rayon into_par_iter().sum() with custom struct

I'm trying to get use Rayon::prelude::into_par_iter to sum up a bunch of instances of a struct. I've implemented std::iter::Sum for the struct, but am still running into an error. Here is my example code;
use std::iter::Sum;
use rayon::prelude::*;
pub struct TestStruct {
val: f32,
}
impl TestStruct {
pub fn new(v: f32) -> Self {
Self { val: v }
}
}
impl<'a> Sum<&'a Self> for TestStruct {
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = &'a Self>,
{
iter.fold(Self { val: 0. }, |a, b| Self {
val: a.val + b.val,
})
}
}
fn main() {
let default_val: f32 = 1.1;
let sum: TestStruct = (0..5).into_par_iter().map(|&default_val| {
TestStruct::new(default_val)
})
.sum();
println!("{}", sum.val);
}
and I am told the trait 'std::iter::Sum' is not implemented for 'TestStruct', but I think I am implementing it. Am I missing something here?
Two small compounded issues. One is that the std::iter::Sum is defined as:
pub trait Sum<A = Self> {
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = A>;
}
The Self here refers to whatever the struct gets the implementation and the default generic parameter has already been filled in. You don't need to specify it any more if implementing Sum for struct itself.
The other is that the map closure parameter default_val, which is an integer, shadows the previous float one with the same name. Since TestStruct::new expects a f32, it leads to a type error.
This works:
impl Sum for TestStruct {
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = Self>,
{
...
}
}
fn main() {
let default_val: f32 = 1.1;
let sum: TestStruct = (0..5)
.into_par_iter()
.map(|_| TestStruct::new(default_val))
.sum();
println!("{}", sum.val);
}

How to call function from certain trait explicitly?

I'd like to know how to call a function from a trait providing that there are several traits with the same function names.
The problem is in the 33 line or
tr1::tr(v);
How I have to express which trait I want to call?
struct V2D {
x: i32,
y: i32
}
impl V2D {
fn new(x: i32, y: i32) -> V2D {
V2D { x, y }
}
}
trait tr1 {
fn tr();
}
trait tr2 {
fn tr();
}
impl tr1 for V2D {
fn tr() {
println!("This is tr1");
}
}
impl tr2 for V2D {
fn tr() {
println!("This is tr2");
}
}
fn main() {
let v = V2D::new(1,2);
tr1::tr(v);
}
The syntax you have used (tr1::tr(v)) would be correct if your method took has a self parameter (Permalink to the playground), but if it doesn't, you need to call it on the type specifying the type and trait explicitly:
<V2D as tr1>::tr()
(Permalink to the playground)
The simplest way would be using fully qualified syntax. In your case tr is an associated function so all you need is a little typecasting:
fn main() {
let v = V2D::new(1,2);
<V2D as tr1>::tr();
<V2D as tr2>::tr();
}
The syntax for methods on the other hand would be something like this:
struct V2D {
x: i32,
y: i32
}
impl V2D {
fn new(x: i32, y: i32) -> V2D {
V2D{x,y}
}
}
trait tr1 {
fn tr(&self);
}
trait tr2 {
fn tr(&self);
}
impl tr1 for V2D {
fn tr(&self) {
println!("This is tr1");
}
}
impl tr2 for V2D {
fn tr(&self) {
println!("This is tr2");
}
}
fn main() {
let v = V2D::new(1,2);
tr1::tr(&v);
}

Require trait implementations to be convertible between each other

I'm trying to have a Rust trait X which requires that anyone implementing X can convert to other implementations of X.
So I'm trying to make the declaration of X enforce this like so:
trait X<T> : From<T> where T: X {}
But the compiler is telling me that it doesn't find any type arguments in my specification of T, because T: X needs some type information T: X<...>. But this way there will always be one type argument too little; e.g.
trait X<T, U> : From<T> where T: X<U> {}
Can I get around this in some way? Doing where T: X<_> is not allowed.
Rather than trying to restrict the implementers, I think it would be simpler to provide the implementation as part of the trait:
trait Length {
fn unit_in_meters() -> f64;
fn value(&self) -> f64;
fn new(value: f64) -> Self;
fn convert_to<T:Length>(&self) -> T {
T::new(self.value() * Self::unit_in_meters() / T::unit_in_meters())
}
}
struct Mm {
v: f64,
}
impl Length for Mm {
fn unit_in_meters() -> f64 { 0.001 }
fn value(&self) -> f64 { self.v }
fn new(value: f64) -> Mm {
Mm{ v: value }
}
}
struct Inch {
v: f64,
}
impl Length for Inch {
fn unit_in_meters() -> f64 { 0.0254 }
fn value(&self) -> f64 { self.v }
fn new(value: f64) -> Inch {
Inch{ v: value }
}
}
fn main() {
let foot = Inch::new(12f64);
let foot_in_mm: Mm = foot.convert_to();
println!("One foot in mm: {}", foot_in_mm.value());
}
Play link
For fun, with the associated_consts feature you can swap the method for a constant conversion factor.
#![feature(associated_consts)]
trait Length {
const UNIT_IN_METERS: f64;
fn value(&self) -> f64;
fn new(value: f64) -> Self;
fn convert_to<T:Length>(&self) -> T {
T::new(self.value() * Self::UNIT_IN_METERS / T::UNIT_IN_METERS)
}
}
struct Mm {
v: f64,
}
impl Length for Mm {
const UNIT_IN_METERS: f64 = 0.001;
fn value(&self) -> f64 { self.v }
fn new(value: f64) -> Mm {
Mm{ v: value }
}
}
struct Inch {
v: f64,
}
impl Length for Inch {
const UNIT_IN_METERS: f64 = 0.0254;
fn value(&self) -> f64 { self.v }
fn new(value: f64) -> Inch {
Inch{ v: value }
}
}
fn main() {
let foot = Inch::new(12f64);
let foot_in_mm: Mm = foot.convert_to();
println!("One foot in mm: {}", foot_in_mm.value());
}
Play link

Resources