I have a generic struct and want to provide a concrete default implementation which will also allow user to override a value of the default field, but am getting compile errors:
struct MyStruct<A, B, C> {
pub a: A,
pub b: B,
pub c: C,
}
impl<A, B, C> MyStruct<A, B, C>
where
A: Trait1,
B: Trait2,
C: Trait3,
{
pub fn foo() {}
}
trait Trait1 {}
trait Trait2 {}
trait Trait3 {}
I can create instances of MyStruct explicitly:
struct SomeA();
impl Trait1 for SomeA {}
struct SomeB();
impl Trait2 for SomeB {}
struct SomeC();
impl Trait3 for SomeC {}
let a = SomeA();
let b = SomeB();
let c = SomeC();
let my_struct = MyStruct { a: a, b: b, c: c }; // compiles
Now I want to implement Default which will also allow overriding a particular field with a different value when necessary (allow partial default?). Not sure on the syntax:
impl Default for MyStruct<SomeA, SomeB, SomeC> {
fn default() -> Self {
...
}
}
Playground
You can achieve this by only implementing Default if A, B, and C all implement Default:
impl <A, B, C> Default for MyStruct<A, B, C> where A: Default, B: Default, C: Default {
fn default() -> Self {
Self {
a: A::default(),
b: B::default(),
c: C::default(),
}
}
}
Related
I think this is a kind of common questions. I've read some solutions but my situation is a bit different...
It complains at line 8. However, I can't change the function signature of new_b as well as everything below the common line. They are all external packages.
So how can I design the function new_a to workaround?
fn main() {
new_a();
}
fn new_a() -> A<'static> {
let b = B {};
A { c: new_b(&b) }
}
pub struct A<'a> {
c: C<'a>,
}
// Below are exteral packages
fn new_b<'a>(b: &'a B) -> C<'a> {
C { b: &b }
}
pub struct B {}
pub struct C<'a> {
b: &'a B,
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=160e63f1300506472b7c1b0811b37453
I have two structs A and B that are exactly similar. I am trying to convert both A and B to another type C. The definitions of A,B and C are given below.
pub struct A {
pub a: i32,
}
pub struct B {
pub a: i32,
}
pub struct C {
pub b: i32,
}
My implementation for converting from A to C is shown below:-
impl From<A> for C {
fn from(a: A) -> C {
C {b: a.a}
}
}
Since A and B both are similar, for converting from B to C, currently I have a duplicate
implementation of the From defined above.
I am looking for a way to make the From implementation generic and only bounded to use
A and B. My implementation here is as follows:-
trait Types {}
impl Types for A {}
impl Types for B {}
impl<T: Types> From<T> for C where T: Types {
fn from(entity: T) -> C {
C { b: entity.a }
}
}
But when I compile a program with the code above, I get the following error,
error[E0609]: no field `a` on type `T`
|
27 | impl<T: Types> From<T> for C where T: Types {
| - type parameter 'T' declared here
I would like to know a way to resolve this error since I have no other choice but to preserve A and B and avoid code duplication.
Usually this is done by macros:
macro_rules! to_C {
($t:ty) => {
impl From<$t> for C {
fn from(a: $t) -> C {
C{b: a.a}
}
}
};
}
to_C!{A}
to_C!{B}
How can I disable struct construction but maintaining pattern matching in Rust?
Let's see an example:
struct OrderedPair(pub u32, pub u32);
impl OrderedPair {
fn new(a: u32, b: u32) -> Self {
if a < b {
Self(a, b)
} else {
Self(b, a)
}
}
}
It's obvious that I want to inhibit the construction of such struct (e.g. OrderedPair(2, 1)) and to use only the new method, in order to preserve the invariant. I know of 3 ways to do this:
Make private the fields
struct OrderedPair(u32, u32);
Add a private dummy field
struct OrderedPair(pub u32, pub u32, ());
Make the struct non-exhaustive
#[non_exhaustive]
struct OrderedPair(pub u32, pub u32);
The issues are that with 1 I cannot access the members at all and with all three I cannot use pattern matching
let OrderedPair(min, max) = my_ordered_pair;
So is there a way to block struct construction but allow pattern matching?
I know that if we declare a mutable variable of that type with public access to members then the invariant can be broken by manually changing the members, but for now avoiding the struct constructor is enough.
Instead of doing pattern matching directly on the fields, you can do it on a returned tupple:
#[derive(Clone, Copy)]
pub struct OrderedPair {
a: u32,
b: u32,
}
impl OrderedPair {
pub fn new(a: u32, b: u32) -> Self {
let (a, b) = if a < b { (a, b) } else { (b, a) };
Self { a, b }
}
pub fn content(self) -> (u32, u32) {
(self.a, self.b)
}
}
If you have a struct like so:
pub struct Foo {
pub a: i32,
pub b: i32,
pub c: String,
// and a bunch of other fields
}
Is there any way to declare a constructor that takes the members of the struct without copy/pasting all umpteen field names/types:
impl Foo {
pub fn new(/* maaaagic */) {
}
}
or do I have to do
impl Foo {
pub fn new(
a: i32,
b: i32,
c: String,
// and a bunch of other args
) {
}
}
If you are using rust-analyzer, there is a generate new assist that does what you want.
Will generate:
impl Foo {
pub fn new(a: i32, b: i32, c: String) -> Self { Self { a, b, c } }
}
Suppose we define a generic struct, with many fields, representing a type-safe state machine using a phantom type:
struct Foo<State> {
a: A,
b: B,
c: C,
//...
state: PhantomData<State>,
}
We can then write a type-safe state transition:
impl Foo<SourceState> {
fn transition(self, extra: X) -> Foo<DestinationState> {
let Foo {a, b, c, state: _} = self;
// do lots of stuff
Foo { a, b, c, state: PhantomData }
}
}
But we need to awkwardly unpack every field and re-pack in in a different structure.
We could also use mem::transmute, although my understanding is that different monomorphizations of the same struct are not guaranteed to have the same memory layout.
I hoped that Foo { state: PhantomData, ..self } would work; alas, it fails to compile.
Is there any canonical, ergonomic, safe way to write this ?
There is no way to do that in a straight forward manner, because they are 2 different types: that's the whole point of your code, actually. To simplify it, I'd do that in 2 steps, with a generic transition being the 2nd one:
use core::marker::PhantomData;
struct Foo<State> {
a: i32,
b: i32,
c: i32,
//...
state: PhantomData<State>,
}
struct SourceState;
struct DestinationState;
impl<Src> Foo<Src> {
fn transition<Dest>(self) -> Foo<Dest> {
let Foo {a, b, c, state: _} = self;
Foo { a, b, c, state: PhantomData }
}
}
impl Foo<SourceState> {
fn to_destination_state(mut self, extra: ()) -> Foo<DestinationState> {
// Do whatever you want with self
self.transition()
}
}
Alternatively, you can abstract the fact that you have a state:
mod stateful {
use core::marker::PhantomData;
pub struct Stateful<T, State> {
pub data: T,
state: PhantomData<State>,
}
impl<T, SrcState> Stateful<T, SrcState> {
pub fn transform<DestState>(self) -> Stateful<T, DestState> {
let Stateful { data, state: _ } = self;
Stateful {
data,
state: Default::default(),
}
}
}
}
struct Data {
a: i32,
b: i32,
c: i32,
}
struct SourceState;
struct DestinationState;
type Foo<State> = stateful::Stateful<Data, State>;
impl Foo<SourceState> {
fn to_destination_state(mut self, extra: ()) -> Foo<DestinationState> {
// Do whatever you want with self.data
self.transform()
}
}