Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reuse common codes for structs?

Tags:

rust

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();
}
like image 309
Hao Li Avatar asked Nov 06 '25 11:11

Hao Li


1 Answers

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();
}
like image 191
Schwern Avatar answered Nov 09 '25 08:11

Schwern