The impl Into<String>
is a shorthand that introduces a type parameter implicitly.
fn create_basic_success_embed(
description: impl Into<String>,
title: Option<impl Into<String>>,
) -> CreateEmbed {
CreateEmbed::new()
.color((0x33, 0xEE, 0x22))
.title(title.unwrap_or("title"))
.description(description)
}
is a shorthand for, essentially:
fn create_basic_success_embed<T: Into<String>, U: Into<String>>(
description: T,
title: Option<U>,
) -> CreateEmbed {
CreateEmbed::new()
.color((0x33, 0xEE, 0x22))
.title(title.unwrap_or("title"))
.description(description)
}
in other words, for any pair of types that support Into<String>
, there’s a specific version of create_basic_success_embed
that works with those two types.
unwrap_or
takes an Option<U>
and a value of the same type U
, and produces a resulting value of type U
.
I don’t know where you get this .unwrap_or(&self, impl Into<String>)
signature; perhaps your IDE hints might display this usage of unwrap_or
as expecting “impl Into<String>
”, or you deduced that yourself, however that’s very different from a function (like description
) that directly declares impl Into<String>
it its own signature. (By the way, it’s also not &self
but an owned self
argument for Option::unwrap_or
!)
If you have a function that needs two values of the same type
fn g<T>(x: T, y: T) {}
then a caller that uses impl Trait
doesn’t change or get around that. These impl Into<String>
occurrences in the signatures aren’t even called “opaque type”s by the way, that term is usually used for “impl Trait
” return types only (a language feature with an – perhaps unfortunately – significantly different meaning).
If you create fn f(x: impl Into<String>, y: impl Into<String>) { … }
, then x
and y
can have different types. And thus, e.g. none of the following works:
fn f(x: impl Into<String>, y: impl Into<String>) {
g(x, y); // doesn't work!
g(x, "hi"); // doesn't work!
g(String::new(), "32"); // doesn't work!
}
Option::unwrap_or
is similar in that it has self: Option<T>
and the other argument default: T
must have the same type.
In your use-case, the issue can easily be solved. The usage of impl Into<String>
on these methods is just a convenience feature anyways! (If you look at the source, you’ll see the first thing the method does is convert it to a String
anyways.) So you can just produce a String
yourself earlier in order to unify the title: impl Into<String>
(which has a type that your functions caller chooses) and &str
for the default value "title"
. Here’s how that could look like:
.title(title.into().unwrap_or_else(|| String::from("title"))
the usage of unwrap_or_else
allows you to avoid the cost of creating the String
from the string literal "title"
in the cases it isn’t needed.