How to call function from certain trait explicitly? - rust

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

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

Multiply trait implementations in 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.

macro_rules!() error: Fix for "the usage of `my_macro!` is likely invalid in impl item context"?

Playground link
I have several different structs grouped together in an enum:
pub enum Ty {
A(AStruct),
B(BStruct)
}
pub struct AStruct {
base: BaseStruct
}
impl AStruct {
base_struct_passthrough_impls!();
pub fn new(x: i32) -> Self {
Self {
base: BaseStruct::new(x)
}
}
}
pub struct BStruct {
base: BaseStruct
}
impl BStruct {
base_struct_passthrough_impls!();
pub fn new(x: i32) -> Self {
Self {
base: BaseStruct::new(x)
}
}
}
All of these types will share a base struct that is common to them all. This base struct will have a lot of methods that I don't want to duplicate for each supertype.
pub struct BaseStruct {
x: i32
}
impl BaseStruct {
pub fn new(x: i32) -> Self {
Self {
x
}
}
pub fn get_x(&self) -> i32 {
self.x
}
}
#[macro_export]
macro_rules! base_struct_passthrough_impls {
() => {
pub fn get_x(&self) -> i32 {
self.base.get_x()
};
}
}
However, trying to use this code results in the following error:
error: macro expansion ignores token `;` and any following
--> src/main.rs:37:10
|
37 | };
| ^
...
46 | base_struct_passthrough_impls!();
| --------------------------------- caused by the macro expansion here
|
= note: the usage of `base_struct_passthrough_impls!` is likely invalid in impl item context
It seems like macro_rules!() is not usable in the impl item context. Is this correct, and if so is there anyway around this restriction? Would a proc macro work here, or would doing something like this work better?
The issue isn't the macro usage, but the definition. You included a trailing semicolon after the function definition created by the macro, which is what causes the error. If you remove it, everything works fine - here's the code:
fn main() {
let types = vec![Ty::A(AStruct::new(32)), Ty::B(BStruct::new(64))];
types.iter().for_each(|item| {
dbg!(match item {
Ty::A(a_struct) => a_struct.get_x(),
Ty::B(b_struct) => b_struct.get_x(),
});
})
}
pub enum Ty {
A(AStruct),
B(BStruct)
}
pub struct BaseStruct {
x: i32
}
impl BaseStruct {
pub fn new(x: i32) -> Self {
Self {
x
}
}
pub fn get_x(&self) -> i32 {
self.x
}
}
#[macro_export]
macro_rules! base_struct_passthrough_impls {
() => {
pub fn get_x(&self) -> i32 {
self.base.get_x()
} // there was an illegal semicolon here
}
}
pub struct AStruct {
base: BaseStruct
}
impl AStruct {
base_struct_passthrough_impls!();
pub fn new(x: i32) -> Self {
Self {
base: BaseStruct::new(x)
}
}
}
pub struct BStruct {
base: BaseStruct
}
impl BStruct {
base_struct_passthrough_impls!();
pub fn new(x: i32) -> Self {
Self {
base: BaseStruct::new(x)
}
}
}

Is there a way to perform an index access to an instance of a struct?

Is there a way to perform an index access to an instance of a struct like this:
struct MyStruct {
// ...
}
impl MyStruct {
// ...
}
fn main() {
let s = MyStruct::new();
s["something"] = 533; // This is what I need
}
You can use the Index and IndexMut traits.
use std::ops::{Index, IndexMut};
struct Foo {
x: i32,
y: i32,
}
impl Index<&'_ str> for Foo {
type Output = i32;
fn index(&self, s: &str) -> &i32 {
match s {
"x" => &self.x,
"y" => &self.y,
_ => panic!("unknown field: {}", s),
}
}
}
impl IndexMut<&'_ str> for Foo {
fn index_mut(&mut self, s: &str) -> &mut i32 {
match s {
"x" => &mut self.x,
"y" => &mut self.y,
_ => panic!("unknown field: {}", s),
}
}
}
fn main() {
let mut foo = Foo { x: 0, y: 0 };
foo["y"] += 2;
println!("x: {}", foo["x"]);
println!("y: {}", foo["y"]);
}
It prints:
x: 0
y: 2
You want to use the Index trait (and its pair IndexMut):
use std::ops::Index;
#[derive(Copy, Clone)]
struct Foo;
struct Bar;
impl Index<Bar> for Foo {
type Output = Foo;
fn index<'a>(&'a self, _index: Bar) -> &'a Foo {
println!("Indexing!");
self
}
}
fn main() {
Foo[Bar];
}

Resources