5

In code below, I am trying to implement a generic struct. What I want to achieve is, for T whose type is String, print self.x value, and for all other types, print both self.x and self.y.

This question is not relevant to trait, I only tried to impl functions for a struct.

use core::fmt::Display;
use core::fmt::Debug;

#[derive(Debug)]
struct Point<T> {
    x: T,
    y: T
}

impl Point<String> {
    fn print(&self) {
        println!("{:?}", self.x);
    }
}

impl<T: Display + Debug> Point<T> {
    fn print(&self) {
        println!("{:?}", self.x);
        println!("{:?}", self.y);
    }
}

fn main() {
    let x = Point{x: String::from("123"), y: String::from("456")};
    let y = Point{x: 123, y: 456};
    //let z = Point{x: vec![1,2,3], y: vec![4,5,6]};
    
    x.print();
    y.print();
    //z.print();
}

However, I got the compile error below:

error[E0592]: duplicate definitions with name `print`

What is the correct way to achieve it?

Moreover, I also tried to use vectors as x and y(the z in main), which is not allow, I want to know the reason.

2
  • you want specialization ? search for it on SO there should be some question about that already Commented Nov 29, 2020 at 11:52
  • Does this answer your question? Generic implementation depending on traits Commented Nov 29, 2020 at 15:26

1 Answer 1

6

Rust doesn't support specialization yet, but there is a tracking issue for the same. But your requirement can be satisfied by checking TypeId.

fn is_string<T: Any>() -> bool {
    TypeId::of::<String>() == TypeId::of::<T>()
}

impl<T: Debug + Any> Point<T> {
    fn print(&self) {
        if is_string::<T>() {
            println!("{:?}", self.x);
        } else {
            println!("{:?}", self.x);
            println!("{:?}", self.y);
        }
    }
}

Playground

This code will also work for vectors. In your code you added a trait bound for Display which is not implemented by Vec.

Sign up to request clarification or add additional context in comments.

1 Comment

Just note that you have to be careful with this because TypeId::of is very literal, so is_string() will return true only for actual String, not for e.g. &'static str. Also, it won't work for any T that contains a non-static lifetime (there was a suggestion to change this, but it got rejected).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.