Consider
mod go;
pub struct Foo<T> {
pub a: i32,
pub b: i32,
pub c: i32,
pub x: i32,
pub y: u32,
pub z: f32,
pub t: T,
}
pub struct Cat{}
pub struct Dog{}
pub fn magic(foo: &Foo<Cat>) -> Foo<Dog> {
let Foo{a, b, c, x, y, z, t} = foo;
Foo{a: *a,
b: *b,
c: *c,
x: *x ,
y: *y,
z: *z,
t: Dog{} }
}
#[test]
pub fn test_00() {
}
I want to copy the object + modify one field.
Is there a short hand to do this without deconstructing all the fields + rebuilding it? It's same to assume that all fields either: has clone, has copy, or is ref.
I think you're looking for the ..
operator.
pub fn magic(foo: &Foo<Cat>) -> Foo<Dog> {
Foo { t: Dog {}, ..*foo }
}
Edit: This won't work in your case because <T>
is different.
2 Likes
Yeah, I hit this kind of thing often when impl From<A> for B
where B is an "updated" or "fixed" version of A, for example A is what serde parses from a raw log, and B has done some extra validation or normalisation.
You'd think I'd remember, but I keep tripping over this. Which tells me it would be nice to be able to do, somehow.
1 Like
You could use unsafe code to do this with std::mem::transmute
but getting the struct sizes right wouldn't be fun. I'm messing around in a Playground right now to see if I can be creative.
..*foo
is good to know even if it doesn't solve the problem.
cuviper
December 14, 2018, 12:56am
6
Even with the same size, the layouts may be different if they're not #[repr(C)]
, breaking transmute
.
You could group the common fields into some inner struct, so there's just one big field to copy.
4 Likes
Yeah, and this is great in combination with #[serde(flatten)]
, but only sometimes.
You can do it if you remove the type parameter and switch to trait objects, but it's a bit of a pain:
use std::any::Any;
struct Foo<'a> {
a: i32,
b: i32,
c: i32,
d: &'a dyn Any
}
struct Cat {
a: i32
}
struct Dog {
a: i32,
b: i32
}
fn magic<'a>(input: &'a Foo<'a>) -> Foo<'a> {
Foo { d: &Dog { a: 0, b: 0 }, ..*input }
}
(this is why having single structural inheritance would be great)
In this specific example, you could also use an Animal enum with Cat and Dog variants in field f - but that's not an answer to the general question.
In your case it probably makes sense to move repeated fields into a separate structure:
#[derive(Clone)]
pub struct A {
pub a: i32,
pub b: i32,
pub c: i32,
pub x: i32,
pub y: u32,
pub z: f32,
}
pub struct Foo<T> {
pub a: A,
pub t: T,
}
Then the operation is simple:
pub fn magic(foo: &Foo<Cat>) -> Foo<Dog> {
Foo {
a: foo.a.clone(),
t: Dog {},
}
}
2 Likes
Nemo157
December 14, 2018, 9:43am
11
An extension for FRU to support changing generic types has been submitted as an RFC:
https://github.com/rust-lang/rfcs/pull/2528
Still a long way from being stable even if it is accepted, but would exactly solve the issue you're having.
6 Likes