4

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.

Harry Zhao
  • 75
  • 5
  • you want specialization ? search for it on SO there should be some question about that already – Stargateur Nov 29 '20 at 11:52
  • Does this answer your question? [Generic implementation depending on traits](https://stackoverflow.com/questions/64955738/generic-implementation-depending-on-traits) – Ibraheem Ahmed Nov 29 '20 at 15:26

1 Answers1

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.

Mihir Luthra
  • 6,059
  • 3
  • 14
  • 39
  • 3
    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](https://github.com/rust-lang/rust/issues/41875)). – user4815162342 Nov 29 '20 at 13:20