Let's say I have two structs that are quite similar:
struct Thing1 {
p1: i32,
p2: i32,
p3: i32
}
struct Thing2 {
p1: i32,
p2: i32,
p3: i32,
metadata: String
}
Having a trait for the common values is quite useful:
trait PValues {
fn p1(&self) -> i32;
fn p2(&self) -> i32;
fn p2(&self) -> i32;
}
impl PValues for Thing1 {
fn p1(&self) -> {self.p1};
fn p2(&self) -> {self.p2};
fn p3(&self) -> {self.p3};
}
impl PValues for Thing2 {
fn p1(&self) -> {self.p1};
fn p2(&self) -> {self.p2};
fn p3(&self) -> {self.p3};
}
However this is laborious, duplicative and error prone. Are there any commonly use rust macros that do this? If not, what is the idiomatic pattern for this?
Related
I have three traits that are dependent on each other, but I can't find a way to define these traits statically without using dyn.
Defining two seems very simple:
pub trait TA<B: TB<Self>> {
fn getB() -> Option<B>;
}
pub trait TB<A: TA<Self>> {
fn getA() -> Option<A>;
}
But defining similar thing with three traits seems impossible (the code bellow doesn't compile):
pub trait TA<B: TB, C: TC> {
fn getB() -> Option<B>;
fn getC() -> Option<C>;
}
pub trait TB<A: TA, C: TC> {
fn getA() -> Option<A>;
fn getC() -> Option<C>;
}
pub trait TC<A: TA, B: TB> {
fn getA() -> Option<A>;
fn getB() -> Option<B>;
}
It seems like with another thought it was easier than I thought.
pub trait TA<B: TB<Self, C>, C: TC<Self, B>> {
fn getB() -> Option<B>;
fn getC() -> Option<C>;
}
pub trait TB<A: TA<Self, C>, C: TC<Self, A>> {
fn getA() -> Option<A>;
fn getC() -> Option<C>;
}
pub trait TC<A: TA<A, Self>, B: TB<B, Self>> {
fn getA() -> Option<A>;
fn getB() -> Option<B>;
}
Edit: #trenctl solution bellow looks much cleaner
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=062b05bf63efb1b6bfb2575bf963ff62
trait Ta {
type B: Tb<A = Self, C = Self::C>;
type C: Tc<A = Self, B = Self::B>;
fn get_b(&self) -> Option<Self::B>;
fn get_c(&self) -> Option<Self::C>;
}
trait Tb {
type A: Ta<B = Self, C = Self::C>;
type C: Tc<B = Self, A = Self::A>;
fn get_a(&self) -> Option<Self::A>;
fn get_c(&self) -> Option<Self::C>;
}
trait Tc {
type A: Ta<C = Self, B = Self::B>;
type B: Tb<C = Self, A = Self::A>;
fn get_a(&self) -> Option<Self::A>;
fn get_b(&self) -> Option<Self::B>;
}
I'm struggling to understand the nuances of the ? operator. Take the following code:
link to playground
use std::{error::Error as StdError, fmt};
#[derive(Debug)]
struct MyError(Box<dyn StdError>);
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
impl StdError for MyError{}
impl From<Box<dyn StdError>> for MyError {
fn from(err: Box<dyn StdError>) -> Self {
MyError(err)
}
}
#[derive(Debug)]
struct RandomErr(String);
impl fmt::Display for RandomErr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
impl StdError for RandomErr{}
fn no_custom() -> Result<(), Box<dyn StdError>> {
Err(RandomErr("hello there".to_owned()))?
}
// This fails to compile
fn custom() -> Result<(), MyError> {
Err(RandomErr("hello there".to_owned()))?
}
I would think that custom() should compile. RandomError is a StdError, so RandomErr should be convertable to MyError since there's an impl for converting from StdError, no?
I would think that custom() should compile. RandomError is a StdError, so RandomErr should be convertable to MyError since there's an impl for converting from StdError, no?
Nope. There is no transitivity in From (or any trait, as far as I know). Rustc generally does what you tell it and no more to avoid problems like combinatory explosions in trait resolution.
So that C: From<B> and B: From<A> does not imply / translate to C: From<A>, you can write that reduced case and will hit E0277 (trait not satisfied):
struct A;
struct B;
struct C;
impl From<A> for B {
fn from(a: A) -> Self { B }
}
impl From<B> for C {
fn from(b: B) -> Self { C }
}
fn main() {
let _: C = From::from(A);
}
I have a function algo which works with a type S1, I also have
a type S2 which contains all of the fields of S1 plus some additional ones.
How should I modify algo to also accept S2 as input without
creating a temporary variable with type S1 and data from S2?
struct Moo1 {
f1: String,
f2: i32,
}
struct Moo2 {
f1: String,
f2: i32,
other_fields: f32,
}
struct S1 {
x: i32,
v: Vec<Moo1>,
}
struct S2 {
x: i32,
v: Vec<Moo2>,
}
//before fn algo(s: &S1)
fn algo<???>(???) {
//work with x and v (only with f1 and f2)
}
Where I'm stuck
Let's assume algo has this implementation (my real application has another implementation):
fn algo(s: &S1) {
println!("s.x: {}", s.x);
for y in &s.v {
println!("{} {}", y.f1, y.f2);
}
}
To access the field in Moo1 and Moo2 I introduce trait AsMoo, and to access x field and v I introduce trait AsS:
trait AsMoo {
fn f1(&self) -> &str;
fn f2(&self) -> i32;
}
trait AsS {
fn x(&self) -> i32;
// fn v(&self) -> ???;
}
fn algo<S: AsS>(s: &AsS) {
println!("s.x: {}", s.x());
}
I'm stuck at the implementation of the AsS::v method. I do not allocate memory to use my algo, but I need a Vec<&AsMoo> in some way.
Maybe I need to return some kind of Iterator<&AsMoo>, but have no idea how to do it and that looks complex for this problem.
Maybe I should use macros instead?
Any problem in computer science can be solved by adding another layer of indirection; at the exception of having too many such layers, of course.
Therefore, you are correct that you miss a S trait to generalize S1 and S2. In S, you can use a feature called associated type:
trait Moo {
fn f1(&self) -> &str;
fn f2(&self) -> i32;
}
trait S {
type Mooer: Moo;
fn x(&self) -> i32;
fn v(&self) -> &[Self::Mooer];
}
The bit type Mooer: Moo; says: I don't quite know what the exact type Mooer will end up being, but it'll implement the Moo trait.
This lets you write:
impl S for S1 {
type Mooer = Moo1;
fn x(&self) -> i32 { self.x }
fn v(&self) -> &[Self::Mooer] { &self.v }
}
impl S for S2 {
type Mooer = Moo2;
fn x(&self) -> i32 { self.x }
fn v(&self) -> &[Self::Mooer] { &self.v }
}
fn algo<T: S>(s: &T) {
println!("s.x: {}", s.x());
for y in s.v() {
println!("{} {}", y.f1(), y.f2());
}
}
And your generic algo knows that whatever type Mooer ends up being, it conforms to the Moo trait so the interface of Moo is available.
I have a few traits with default implementations that require the same methods, which happen to be field getters.
trait AddPosition<T: Display>{
fn x(&self) -> T;
fn y(&self) -> T;
fn add(&self){
println!("{:}", self.x()+self.x());
}
}
trait SubPosition<T: Display>{
fn x(&self) -> T;
fn y(&self) -> T;
fn sub(&self){
println!("{:}", self.x()-self.y());
}
}
Instead of manually repeating the same code for each trait implementation, can I have something like this?
impl AddPosition<i32>, SubPosition<i32> for Point{
fn x(&self) -> i32{ self.x }
fn y(&self) -> i32{ self.y }
}
The best option is probably to factor out the fact that your objects can have a position:
trait Position<T: Display> {
fn x(&self) -> T;
fn y(&self) -> T;
}
// trait AAA: BBB --> means AAA must implement BBB
trait AddPosition<T: Add<Output=T> + Display>: Position<T> {
fn add(&self){
println!("{:}", self.x()+self.x()); // ?
}
}
trait SubPosition<T: Sub<Output=T> + Display>: Position<T> {
fn sub(&self){
println!("{:}", self.x()-self.y()); // ?
}
}
struct MyPosition {
x: i32,
y: i32,
}
impl Position<i32> for MyPosition {
fn x(&self) -> i32 { self.x }
fn y(&self) -> i32 { self.y }
}
impl SubPosition<i32> for MyPosition {}
impl AddPosition<i32> for MyPosition {}
(Playground)
However, I fail to understand how your code really makes sense (? annotated lines). If this is just for the sake of the minimal example, this is totally fine; however, if this is meant for any serious code, you may want to look into the Add and Sub trait, which will allow you to benefit from operator overloading + and -. Even if you don't use those traits directly, they may inspire you for meaningful signatures of a potential add(&self, rhs: &P) -> P function (where P: Position<T>).
I have a custom type pub struct Foo and I'd like to be able to say strings can be converted to Foo types. I'm trying to do impl<'a> Into<Foo> for &'a str, but I know from this answer that I can't do that. What other options do I have?
For context, I'm trying to do something like
trait Foo {
type ArgType;
fn new<I: Into<Self::ArgType>>(arg: I) -> Self;
}
struct MyType;
impl Into<MyType> for str {
fn into(self) -> MyType { MyType }
}
struct Bar;
impl Foo for Bar {
type ArgType = MyType;
fn new<I: Into<MyType>>(arg: I) -> Bar { Bar }
}
As Chris Morgan noted, FromStr is an option, From<&str> would be another. The latter would give you a builtin implementation of Into<Foo> for &str, too (because there is a blanket impl of Into<U> For T where U: From<T>).