简体   繁体   中英

What is the difference between `dyn` and generics?

I'm reading some code and it has a consume function which makes it possible for me to pass my own function f .

fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R>
    where
        F: FnOnce(&mut [u8]) -> Result<R>,

I wrote some similar code, but like this:

pub fn phy_receive(
        &mut self,
        f: &mut dyn FnMut(&[u8])
    ) -> u8 {

and to be fair I don't know what is the difference, aside from FnOnce vs FnMut . What is the difference between using dyn vs a generic type paramater to specify this function?

Using dyn with types results in dynamic dispatch (hence the dyn keyword), whereas using a (constrained) generic parameter results in monomorphism.

General explanation

Dynamic dispatch

Dynamic dispatch means that a method call is resolved at runtime. It is generally more expensive in terms of runtime resources than monomorphism.

For example, say you have the following trait

trait MyTrait {
  fn f(&self);
  fn g(&self);
}

and a struct MyStruct which implements that trait. If you use a dyn reference to that trait (eg &dyn MyTrait ), and pass a reference to a MyStruct object to it, what happens is the following:

  • A "vtable" data structure is created. This is a table containing pointers to the MyStruct implementations of f and g .
  • A pointer to this vtable is stored with the &dyn MyTrait reference, hence the reference will be twice its usual size; sometimes &dyn references are called "fat references" for this reason.
  • Calling f and g will then result in indirect function calls using the pointers stored in the vtable.

Monomorphism

Monomorphism means that the code is generated at compile-time. It's similar to copy and paste. Using MyTrait and MyStruct defined in the previous section, imagine you have a function like the following:

fn sample<T: MyTrait>(t: T) { ... }

And you pass a MyStruct to it:

sample(MyStruct);

What happens is the following:

  • During compile time, a copy of the sample function is created specifically for the MyStruct type. In very simple terms, this is as if you copied and pasted the sample function definition and replaced T with MyStruct :
fn sample__MyStruct(t: MyStruct) { ... }
  • The sample(MyStruct) call gets compiled into sample__MyStruct(MyStruct) .

This means that in general, monomorphism can be more expensive in terms of binary code size (since you are essentially duplicating similar chunks of code, but for different types), but there's no runtime cost like there is with dynamic dispatch.

Your example

Since FnMut is just a trait, the above discussion applies directly to your question. Here's the trait definition:

pub trait FnMut<Args>: FnOnce<Args> {
    pub extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}

Disregarding the extern "rust-call" weirdness, this is a trait just like MyTrait above. This trait is implemented by certain Rust functions, so any of those functions is analogous to MyStruct from above. Using &dyn FnMut<...> will result in dynamic dispatch, and using <T: FnMut<...>> will result in monomorphism.

My 2 cents and general advice

Certain situations will require you to use a dynamic dispatch. For example, if you have a Vec of external objects implementing a certain trait, you have no choice but to use dynamic dispatch. For example, Vec<Box<dyn Debug>> .

If those objects are internal to your code, though, you could use an enum type and monomorphism.

Apart from that, all things being equal, my advice is to use monomorphism if you can, and dynamic dispatch if you have to. Personally, I've noticed that in much of my code, I only end up calling the function once or twice. If you're only calling it once, you're getting monomorphism for free, since the binary code will only be generated once. On the other hand, using a dyn reference might result in simpler code — your mileage may vary.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM