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}
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 in my project a struct A which is logically related to a struct B from a different crate. Both have internally an optional sub-struct (C / D).
Let's say for this example they have this struct definition:
struct D {
name: Option<String>
}
struct B {
spec: Option<D>
}
struct C {
name: Option<String>
}
struct A {
spec: Option<C>
}
Now I want to implement the Into-trait on A into B:
impl Into<D> for C {
fn into(self) -> D {
D {
name: self.name
}
}
}
impl Into<B> for A {
fn into(self) -> B {
B {
spec: self.spec.into()
}
}
}
But rust does not allow it:
error[E0277]: the trait bound `std::option::Option<D>: From<std::option::Option<C>>` is not satisfied
--> src\model\k8s.rs:615:29
|
615 | spec: self.spec.into()
| ^^^^ the trait `From<std::option::Option<C>>` is not implemented for `std::option::Option<D>`
|
= help: the following implementations were found:
<std::option::Option<&'a T> as From<&'a std::option::Option<T>>>
<std::option::Option<&'a mut T> as From<&'a mut std::option::Option<T>>>
<std::option::Option<&'a tracing_core::span::Id> as From<&'a tracing::span::EnteredSpan>>
<std::option::Option<&'a tracing_core::span::Id> as From<&'a tracing::span::Span>>
and 10 others
= note: required because of the requirements on the impl of `Into<std::option::Option<D>>` for `std::option::Option<C>`
Although I provide a custom implementation for Into on C it only checks for From. Which I can't provide as D is another crate. I have to write this:
spec: if let Some(v) = self.spec { Some(v.into()) } else { None }
Now the question: Is there a better way I am missing? If not, why is it such a hassle to into() Options?
The issue is that you're calling Into::into on the Option<C> type rather than the type the Option holds (C).
You can use the Option::map method which operates on the inner type of the Option:
impl Into<B> for A {
fn into(self) -> B {
B {
spec: self.spec.map(Into::into)
}
}
}
There is no blanket impl<T, U: Into<T>> Into<Option<T>> for Option<U> (or the From equivalent) in the standard library, that's why you can't use Into trait to turn Option<T> into Option<U> directly on the Option and have to rely on Option::map or some other way (like your last snippet) of extracting the inner type instead.
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(),
}
}
}
Just started working with Rust a couple of days ago. I'm porting some C++ code right now, and this question seems to be the reverse of the common "expected struct, got type" sort. This code involves two classes, a container class A and a client class B.
use std::vec::Vec;
struct A<T:FooTrait> {
children: Vec<*mut T>
}
impl <T:FooTrait> A<T> {
fn insert(&mut self, val: &mut T) -> Handle<T> {
self.children.push(val);
return Handle{owner: self};
}
}
struct B {
handle: Handle<B>
}
trait FooTrait {
fn set_handle<T:FooTrait>(&mut self, h: Handle<T>);
}
impl FooTrait for B {
fn set_handle<B:FooTrait>(&mut self, h: Handle<B>) {
self.handle = h; // <-- Here is the problem
}
}
struct Handle<T:FooTrait> {
owner: *mut A<T>
}
impl <T:FooTrait> Default for Handle<T> {
fn default()->Handle<T> {
Handle {
owner: std::ptr::null_mut()
}
}
}
fn main() {
let mut foo = A::<B> { children: Default::default() };
let mut b = B{handle: Default::default()};
b.handle = foo.insert(&mut b);
}
Getting the error:
error[E0308]: mismatched types
--> src/main.rs:23:23
|
22 | fn set_handle<B:FooTrait>(&mut self, h: Handle<B>) {
| - this type parameter
23 | self.handle = h;
| ^ expected struct `B`, found type parameter `B`
|
= note: expected struct `Handle<B>` (struct `B`)
found struct `Handle<B>` (type parameter `B`)
Simplified version (playground):
use std::marker::PhantomData;
struct B {
handle: PhantomData<B>,
}
trait FooTrait {
fn set_handle<T: FooTrait>(&mut self, h: PhantomData<T>);
}
impl FooTrait for B {
fn set_handle<BType: FooTrait>(&mut self, h: PhantomData<BType>) {
self.handle = h;
}
}
Note that I've changed the name of the type parameter in set_handle. Now the error is more clear:
error[E0308]: mismatched types
--> src/lib.rs:13:23
|
12 | fn set_handle<BType: FooTrait>(&mut self, h: PhantomData<BType>) {
| ----- this type parameter
13 | self.handle = h;
| ^ expected struct `B`, found type parameter `BType`
|
= note: expected struct `std::marker::PhantomData<B>`
found struct `std::marker::PhantomData<BType>`
In your case, the error is essentially the same, since the generic parameter is a new type, which shadowed the global struct B.
Now, what to do? It depends on what do you want to get.
If the struct B definition is correct and set_handle need to handle only Bs, just remove the generic parameter from set_handle (playground):
trait FooTrait {
fn set_handle(&mut self, h: PhantomData<B>);
}
impl FooTrait for B {
fn set_handle(&mut self, h: PhantomData<B>) {
self.handle = h;
}
}
If the struct B definition is correct, but set_handle must be able to use different handler types depending on Self, use an associated type (playground):
trait FooTrait {
type T: FooTrait;
fn set_handle(&mut self, h: PhantomData<Self::T>);
}
impl FooTrait for B {
type T = B;
fn set_handle(&mut self, h: PhantomData<B>) {
self.handle = h;
}
}
Now the implementation block will choose what kind of argument (handler, in your case) it will get.
If the set_handle definition is correct, i.e. the caller can choose the type of handler, then struct B must be generic, too. However, in this case you essentially can't use the trait-based approach, since the trait has to be generic too, and you will not be able to simply use it in any generic bound without providing parameters (which has to be bound too, ad infinitum).
There are two different B here. The original B you defined in struct B, and the second <B:FooTrait> type parameter. The second is shadowing the first. Here is how the compiler sees it:
impl FooTrait for B {
fn set_handle<AnyFoo:FooTrait>(&mut self, h: Handle<AnyFoo>) {
self.handle = h; // <-- Here is the problem
}
}
The way you've defined things, FooTrait::set_handle is supposed to work with any type that implements FooTrait, but the handle field of B can only store a Handle<B>. You need to rethink what you want FooTrait to do and how B satisfies it.
I am writing a struct that functions as a thin wrapper over an existing struct. The existing struct isn't fixed, so I've written it as a type parameter (see struct B below). I would like B to preserve convertibility (i.e. From/Into) based on the internal wrapped type, i.e. if A1 is convertible to A then B<A1> should be convertible to B<A> as well.
I tried the following code:
pub struct A {}
pub struct A1 {}
impl From<A1> for A {
fn from(a1: A1) -> Self {
Self {}
}
}
pub struct B<T> {
t: T,
other_stuff: String,
}
impl<T, U: Into<T>> From<B<U>> for B<T> {
fn from(b: B<U>) -> Self {
Self {
t: b.t.into(),
other_stuff: b.other_stuff,
}
}
}
pub fn main() {
// I would like this to work:
let ba1: B<A1> = B{ t: A1{}, other_stuff: "abc".to_owned() };
let ba: B<A> = ba1.into();
}
It produces a compilation error:
error[E0119]: conflicting implementations of trait `std::convert::From<B<_>>` for type `B<_>`:
--> src/main.rs:13:1
|
13 | impl<T, U: Into<T>> From<B<U>> for B<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<T> std::convert::From<T> for T;
I think I understand why the error arises (because converting B<A> to B<A> is already defined), but how may I rewrite my code to avoid the error?