How can I implement a function differently depending on if a generic type implements a trait or not?

Multi tool use
Multi tool use


How can I implement a function differently depending on if a generic type implements a trait or not?



I'd like to make the implementation of do_something conditional based on if the generic type T implements Debug or not. Is there any way to do something like this?


do_something


T


Debug


struct A(i32);

#[derive(Debug)]
struct B(i32);

struct Foo<T> {
data: T,
/* more fields */
}

impl<T> Foo<T> {
fn do_something(&self) {
/* ... */
println!("Success!");
}

fn do_something(&self)
where
T: Debug,
{
/* ... */
println!("Success on {:?}", self.data);
}
}

fn main() {
let foo = Foo {
data: A(3), /* ... */
};
foo.do_something(); // should call first implementation, because A
// doesn't implement Debug

let foo = Foo {
data: B(2), /* ... */
};
foo.do_something(); // should call second implementation, because B
// does implement Debug
}



I think one way to do this is to create a trait where we have to define do_something(&Self), but I'm not sure. My code snippet is what I will try first.


do_something(&Self)





play.rust-lang.org/… ?
– Stargateur
Jul 2 at 17:41





@Stargateur what I mean is to do A if T implements a Trait, and do B if T doesn't implement a Trait, all of this under one common name like do_something(&Self)
– Kevin Del Castillo Ramirez
Jul 2 at 17:43



do_something(&Self)





It's not possible both must implement the trait in this context. :/ Maybe you should read about trait and how to use them.
– Stargateur
Jul 2 at 17:51






Yeah, I supposed it, but just wondering if I didn't know something ultra advanced, but it will be cool to see something like if T impl Debug { A } else { B } inside functions, I think it's possible because its like conditional compilation, all of this can be checked at compile time.
– Kevin Del Castillo Ramirez
Jul 2 at 17:59


if T impl Debug { A } else { B }




1 Answer
1



Here is a solution based on the nightly feature specialization:


#![feature(specialization)]

use std::fmt::Debug;

struct A(i32);

#[derive(Debug)]
struct B(i32);

struct Foo<T> {
data: T,
/* more fields */
}

trait Do {
fn do_something(&self);
}

impl<T> Do for Foo<T> {
default fn do_something(&self) {
/* ... */
println!("Success!");
}
}

impl<T> Do for Foo<T>
where
T: Debug,
{
fn do_something(&self) {
/* ... */
println!("Success on {:?}", self.data);
}
}

fn main() {
let foo = Foo {
data: A(3), /* ... */
};
foo.do_something(); // should call first implementation, because A
// doesn't implement Debug

let foo = Foo {
data: B(2), /* ... */
};
foo.do_something(); // should call second implementation, because B
// does implement Debug
}



The first step is to create a trait which defines do_something(&self). Now, we define two impls of this trait for Foo<T>: a generic "parent" impl which is implemented for all T and a specialized "child" impl which is only implemented for the subset where T implements Debug. The child impl may specialize items from the parent impl. These items we want to specialize need to be marked with the default keyword in the parent impl. In your example, we want to specialize do_something.


do_something(&self)


impl


Foo<T>


impl


T


impl


T


Debug


impl


impl


default


impl


do_something





I had something like this in mind but I didn't know about specialization feature.
– Kevin Del Castillo Ramirez
Jul 2 at 19:01






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

xAx9G2yy2Sg
CpN,T s4Tp oOTV,YYQhwDiui NYuM3qdjgvn,bW q,Z6AbMm,er55lsX5C7qE

Popular posts from this blog

PHP contact form sending but not receiving emails

Do graphics cards have individual ID by which single devices can be distinguished?

Create weekly swift ios local notifications