Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

262
Views
Why does this closure require inlining or `dyn`? What does `dyn` do here?

I'm confused about what's going on with lifetimes below:

struct Foo{}
impl Foo {
    fn foo(&self, _s: &str) {}
}

fn main() {
    let foo = &Foo{};
    let closure = |s| foo.foo(s);

    // Part 1: error message about wrong lifetime in FnOnce
    take_closure(closure); 

    // Part 2: no error when inlined
    take_closure(|s| foo.foo(s));

    // Part 3: no error when `dyn`d and given explicit signature
    let closure: &dyn Fn(&str) -> _ = &|s| foo.foo(s);
    take_closure(closure);
}

fn take_closure(f: impl Fn(&str) -> ()) {
    let s = get_string();
    f(&s)
}

fn get_string() -> String {
    "".to_string()
}

playground

  1. Why does Part 1 error?
  2. Why does Part 2 not error?
  3. Why does Part 3 not error and what actually happens in part 3? Does Rust make a vtable? The LLVM outputs differ between 2 and 3
  4. Is there a better way? Inlining is ugly and dyn is both ugly and makes me wonder about what it actually does.
over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

Why does Part 1 error?

Rust's type inference is not great at deciding what type a closure should have, when the closure is declared separately from where it is used. When the closure accepts references, the compiler often assumes that there is some specific lifetime that will be involved, not “any lifetime the caller cares to provide” as is actually required here.

In fact, there's an active Rust RFC to improve this by adding another way to specify lifetime parameters on closures. (The RFC also contains an example where making the opposite lifetime assumption would not work.)

what actually happens in part 3? Does Rust make a vtable?

Yes, there's a vtable involved whenever you use dyn. That's not especially relevant to the root cause here; it's just that the elided lifetime in dyn Fn(&str) got resolved the way you needed rather than the way you didn't.

Is there a better way? Inlining is ugly and dyn is both ugly and makes me wonder about what it actually does.

Placing a closure directly in the function call expression that uses it is very common Rust style, and I recommend you stick to it whenever possible, since it's also the way that works well with type inference.

As a workaround in the case where you need to use a closure more than once, you could pass the closure through a function that constrains its type:

fn string_acceptor<F: Fn(&str) -> ()>(f: F) -> F {
    f
}

...

    let foo = &Foo{};
    let closure = string_acceptor(|s| foo.foo(s));
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!