问题
I want to reuse codes for structs. For example:
use std::fmt::Display;
struct CommonStruct<T: Display> {
// could have more fields
data: T
}
struct A<T: Display> {
com: CommonStruct<T>,
age: i32
}
struct B<T: Display> {
com: CommonStruct<T>,
name: String
}
impl<T: Display> A<T> {
// could be more common functions
fn print_data(&self) {
// could be more complicated
println!("data: {}", self.com.data);
}
}
impl<T: Display> B<T> {
// could be more common functions
fn print_data(&self) {
// could be more complicated
println!("data: {}", self.com.data);
}
}
fn main() {
let a = A{ com: CommonStruct{data: 10}, age: 0 };
a.print_data();
let b = B{ com: CommonStruct{data: 12}, name: "123".to_string() };
b.print_data();
}
where A
and B
have some common fields packed by CommonStruct
and some common functions (e.g., print_data
).
I tried to use trait
but cannot figure out a solution:
use std::fmt::Display;
struct CommonStruct<T: Display> {
// could have more fields
data: T
}
struct A<T: Display> {
com: CommonStruct<T>,
age: i32
}
struct B<T: Display> {
com: CommonStruct<T>,
name: String
}
trait Common {
// could be more common functions
fn print_data(&self) {
print_data(&self)
}
}
impl<T: Display> Common for A<T> {
}
impl<T: Display> Common for B<T> {
}
fn print_data(t: &Common) {
// could be more complicated
println!("data: {}", t.com.data);
}
fn main() {
let a = A{ com: CommonStruct{data: 10}, age: 0 };
a.print_data();
let b = B{ com: CommonStruct{data: 12}, name: "123".to_string() };
b.print_data();
}
回答1:
Since print_data
only uses the CommonStruct, and A and B share no other fields, make it an implementation of CommonStruct and call it directly.
impl <T: Display> CommonStruct<T> {
fn print_data(&self) {
println!("data: {}", self.data);
}
}
fn main() {
let a = A{ com: CommonStruct{data: 10}, age: 0 };
a.com.print_data();
let b = B{ com: CommonStruct{data: 12}, name: "123".to_string() };
b.com.print_data();
}
Alternatively, make a trait which has a concrete implementation of print_data
which relies on a method to get the data.
trait HasData<T: Display> {
fn get_data(&self) -> &T;
fn print_data(&self) {
// could be more complicated
println!("data: {}", self.get_data());
}
}
Then each only has to implement how to get the data.
impl<T: Display> HasData<T> for CommonStruct<T> {
fn get_data(&self) -> &T {
return &self.data;
}
}
impl<T: Display> HasData<T> for A<T> {
fn get_data(&self) -> &T {
return &self.com.data;
}
}
impl<T: Display> HasData<T> for B<T> {
fn get_data(&self) -> &T {
return &self.com.data;
}
}
fn main() {
let a = A{ com: CommonStruct{data: 1}, age: 0 };
a.print_data();
let b = B{ com: CommonStruct{data: 2}, name: "123".to_string() };
b.print_data();
let c = CommonStruct{data: 3};
c.print_data();
}
回答2:
I saw that you wanted to use traits. I've included a working example below.
However, traits are used to implement shared behavior. A trait must be implemented on each type you wish to have the shared behavior. So, you do have to impl
a separate print_data
function for a given type.
use std::fmt::Display;
// `Common` structure of some type `T`.
struct Common<T: Display> {
data: T,
}
// `Printable` trait used to print `data`.
trait Printable {
fn print_data(&self);
}
struct A {
common: Common<String>,
}
impl A {
fn new(s: &str) -> A {
A {
common: Common { data: s.to_owned() },
}
}
}
// Implement `Printable the trait for A`.
impl Printable for A {
fn print_data(&self) {
println!("A.common.data: {}", self.common.data)
}
}
struct B {
common: Common<i32>,
}
// Implement the `Printable` trait for `B`.
impl Printable for B {
fn print_data(&self) {
println!("B.common.data: {}", self.common.data)
}
}
So that's traits, but if you must call the same function to print the data, then maybe something like the following can work for you. It defines an enum
with three variants. You can then match
on a particular variant as demonstrated by print_all_data
.
use std::path::PathBuf;
struct G {
path: PathBuf,
common: Common<String>,
}
enum C {
D(A),
E(B),
F(G),
}
fn print_all_data(c: C) {
match c {
C::D(a) => println!("{}", a.common.data),
C::E(b) => println!("{}", b.common.data),
C::F(g) => println!("{} {:?}", g.common.data, g.path)
}
}
fn main() {
let a = A::new("hello");
a.print_data();
let b = B {
common: Common { data: 42 },
};
b.print_data();
let g = G {
path: PathBuf::from("some/path/file.txt"),
common: Common {data: "some_data".to_owned()}
};
let cfg = C::F(g);
print_all_data(cfg);
print_all_data(C::D(a));
print_all_data(C::E(b));
}
来源:https://stackoverflow.com/questions/64733353/how-to-reuse-common-codes-for-structs