Hi there, I'm having some issues trying to use a complex function as an attribute in a struct. The function I want to have as an attribute is this:
fn the_fn<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
input.into() // Example, just to get the header
}
And I've thought of using a Box
, but seems difficult to know the type of that attribute. Even if I change the input type to &str
(which is possible in my use case) I get issues with lifetime parameters.
Here is the play code: Rust Playground
How can I do it properly?
Unfortunately you can't because generics don't exist at runtime. We call this monomorphization. At compile time, rust "instantiates" a concrete copy of every generic function for every set of concrete type arguments used by the program. For example, given:
fn debug<A: Debug>(a: A) {
println!("{:?}", &a);
}
fn main() {
debug(1u32);
debug("my string");
}
Rust will instantiate debug::<u32>
and debug::<&'static str>
but the compiled program won't know anything about, e.g., debug::<String>
.
This is why rust has dynamic dispatch (trait objects, e.g., &Debug
). The following program will only instantiate a single debug
function.
fn debug(a: &Debug) {
println!("{:?}", a);
}
fn main() {
debug(&1u32);
debug(&"my string");
}
However, that won't work in your case because:
-
Into
requires that all types on which it is implemented be Sized
. Sized
is a marker trait implemented on types whose size is known at compile time. Into
imposes this constraint because Into::into
takes self
by-value (consumes it) and, in today's rust, there's no way to take a "dynamically" (known only at runtime) sized type (DST) by value.
- Traits bounded by
Sized
cannot be turned into trait objects because the size of a trait object is not known at compile time.
My explanation of dynamically sized/statically sized types is very light on details so please say so if you're confused.
OK, I get it, I will use Fn(&str) -> String+ Send + Sync
, since it's OK in my current situation. Thanks for the explanation!