The trait bound usually relates to the kinds of operations you need to be able to do inside of the function, and the kinds of types you want to instantiate it with. So a possible logical way is to have an implementation of your function that works for two (or more) concrete types already, and have (dummy) use-cases that call them. Then you'd try to merge both functions into one, using generics in places where the types differ. Finally, you can often follow compiler errors for hints for the trait bounds necessary; though that might not work perfectly for method calls (because method call syntax in turn desugars by using the available trait bounds).
To illustrate, if you have
fn print_i32(x: i32) {
println!("{x}");
}
// contains the same code, just different type signature
fn print_str_ref(x: &str) {
println!("{x}");
}
fn user() {
let x: i32 = 42;
print_i32(x);
let x: &str = "hello";
print_str_ref(x);
}
and want to turn this into a single generic print_anything
, you can see x
has different types, so let's use a generic and first make sure we have our use-case set up correctly
fn print_anything<T>(x: T) {
todo!()
}
fn user() {
let x: i32 = 42;
print_anything(x);
let x: &str = "hello";
print_anything(x);
}
now we fill in the implementation, which will give compilation errors. While addressing those, we also make sure that the use-case doesn’t break:
fn print_anything<T>(x: T) {
println!("{x}");
}
error[E0277]: `T` doesn't implement `std::fmt::Display`
--> src/lib.rs:2:15
|
2 | println!("{x}");
| ^^^ `T` cannot be formatted with the default formatter
|
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider restricting type parameter `T`
|
1 | fn print_anything<T: std::fmt::Display>(x: T) {
| +++++++++++++++++++
In this case, the compiler suggestion is already on-point and this works:
fn print_anything<T: std::fmt::Display>(x: T) {
println!("{x}");
}
fn user() {
let x: i32 = 42;
print_anything(x);
let x: &str = "hello";
print_anything(x);
}
Though of course, it isn’t always that easy.
As for your use-case, you could have tried the same general approach; feel free to share your actual code, and maybe we can point out strategies to cope with issues that could have come up.