为什么这个闭包需要内联或 `dyn`? `dyn` 在这里做什么?
Why does this closure require inlining or `dyn`? What does `dyn` do here?
我对以下生命周期的情况感到困惑:
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()
}
- 为什么第 1 部分会出错?
- 为什么第 2 部分没有错误?
- 为什么第 3 部分没有错误,第 3 部分实际发生了什么? Rust 会创建 vtable 吗? LLVM 输出在 2 和 3
之间不同
- 有没有更好的方法?内联是丑陋的,
dyn
既丑陋又让我想知道它到底做了什么。
Why does Part 1 error?
Rust 的类型推断在决定闭包应该具有什么类型时不是很好,当闭包是从使用它的地方单独声明的。当闭包接受引用时,编译器通常假定将涉及一些 特定的 生命周期,而不是此处实际要求的“调用者关心提供的任何生命周期”。
事实上,an active Rust RFC to improve this 通过添加另一种方法来指定闭包的生命周期参数。 (RFC 还包含一个示例,其中做出相反的生命周期假设是行不通的。)
what actually happens in part 3? Does Rust make a vtable?
是的,每当您使用 dyn
时都会涉及一个 vtable。这与这里的根本原因并不特别相关。只是 dyn Fn(&str)
中省略的生命周期以您需要的方式得到了解决,而不是您不需要的方式。
Is there a better way? Inlining is ugly and dyn
is both ugly and makes me wonder about what it actually does.
将闭包直接放在使用它的函数调用表达式中是非常常见的 Rust 风格,我建议您尽可能坚持使用它,因为它也是有效的方式很好的类型推断。
作为在需要多次使用闭包的情况下的解决方法,您可以通过一个限制其类型的函数传递闭包:
fn string_acceptor<F: Fn(&str) -> ()>(f: F) -> F {
f
}
...
let foo = &Foo{};
let closure = string_acceptor(|s| foo.foo(s));
我对以下生命周期的情况感到困惑:
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()
}
- 为什么第 1 部分会出错?
- 为什么第 2 部分没有错误?
- 为什么第 3 部分没有错误,第 3 部分实际发生了什么? Rust 会创建 vtable 吗? LLVM 输出在 2 和 3 之间不同
- 有没有更好的方法?内联是丑陋的,
dyn
既丑陋又让我想知道它到底做了什么。
Why does Part 1 error?
Rust 的类型推断在决定闭包应该具有什么类型时不是很好,当闭包是从使用它的地方单独声明的。当闭包接受引用时,编译器通常假定将涉及一些 特定的 生命周期,而不是此处实际要求的“调用者关心提供的任何生命周期”。
事实上,an active Rust RFC to improve this 通过添加另一种方法来指定闭包的生命周期参数。 (RFC 还包含一个示例,其中做出相反的生命周期假设是行不通的。)
what actually happens in part 3? Does Rust make a vtable?
是的,每当您使用 dyn
时都会涉及一个 vtable。这与这里的根本原因并不特别相关。只是 dyn Fn(&str)
中省略的生命周期以您需要的方式得到了解决,而不是您不需要的方式。
Is there a better way? Inlining is ugly and
dyn
is both ugly and makes me wonder about what it actually does.
将闭包直接放在使用它的函数调用表达式中是非常常见的 Rust 风格,我建议您尽可能坚持使用它,因为它也是有效的方式很好的类型推断。
作为在需要多次使用闭包的情况下的解决方法,您可以通过一个限制其类型的函数传递闭包:
fn string_acceptor<F: Fn(&str) -> ()>(f: F) -> F {
f
}
...
let foo = &Foo{};
let closure = string_acceptor(|s| foo.foo(s));