如何参考通用返回值中关闭的类型?

发布于 2025-02-06 00:59:37 字数 1509 浏览 3 评论 0 原文

我有一个包含一个函数的结构,可以说 f:fn() - >字符串。我想在其构造函数中将其初始化为特定的默认函数,稍后可以将其覆盖,如果他们愿意的话。

struct Builder<F> {
    func: F,
}

fn new_builder() -> ??? {
    let hello = "hello".to_owned();
    Builder { func: move || hello }
}

impl<F: Fn() -> String> Builder<F> {
    fn build(self) -> String {
        (self.func)()
    }
}

但是如何编写 new_builder()的返回类型,因为 || {} 有匿名类型吗?我尝试了 - &gt; Builder&lt; _&gt; 但失败(游乐场),并提出了一个甚至在语法上都不有效的解决方案:

error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
 --> src/lib.rs:5:29
  |
5 | fn new_builder() -> Builder<_> {
  |                     --------^-
  |                     |       |
  |                     |       not allowed in type signatures
  |                     help: replace with the correct return type: `Builder<[closure@src/lib.rs:6:21: 6:26]>`

For more information about this error, try `rustc --explain E0121`.

我知道我可以通过制作 builder 带有一些拳击:

struct Builder {
    func: Box<dyn Fn() -> ()>,
}

但是,这会在中间遇到额外的运行时 开销。分配和间接形式的形式,可能会使编译器更难优化,例如,直列调用 func 。在我的实际情况下,这种解决方法非常快,但是我仍然想知道Rust是否可以在这里坚持使用纯粹的静态解决方案。

有没有办法在不诉诸参考或拳击的情况下进行这项工作?

I have a struct that contains a function, let's say of type F: Fn() -> String. And I want to initialize it in its constructor to a particular default function, which can later be overridden by the caller if they like.

struct Builder<F> {
    func: F,
}

fn new_builder() -> ??? {
    let hello = "hello".to_owned();
    Builder { func: move || hello }
}

impl<F: Fn() -> String> Builder<F> {
    fn build(self) -> String {
        (self.func)()
    }
}

But how do I write the return type of new_builder(), since || {} has an anonymous type? I tried with -> Builder<_> but that fails (playground), and suggests a solution that's not even syntactically valid:

error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
 --> src/lib.rs:5:29
  |
5 | fn new_builder() -> Builder<_> {
  |                     --------^-
  |                     |       |
  |                     |       not allowed in type signatures
  |                     help: replace with the correct return type: `Builder<[closure@src/lib.rs:6:21: 6:26]>`

For more information about this error, try `rustc --explain E0121`.

I know I can solve it by making Builder non-generic with some boxing:

struct Builder {
    func: Box<dyn Fn() -> ()>,
}

But that incurs additional runtime overhead in the form of allocations and indirections, and might make it harder for the compiler to optimize, e.g. inline calls to func. This workaround is plenty fast in my practical situation, but I'm still wondering if Rust lets me stick to a purely static solution here.

Is there a way to make this work without resorting to references or boxing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

飘过的浮云 2025-02-13 00:59:37

这里的主要问题是闭合的类型无法用代码< /a>。

幸运的是,正是由于这个原因, impl return类型存在关键字:

struct Builder<F> {
    func: F,
}

fn new_builder() -> Builder<impl FnOnce() -> String> {
    let hello = "hello".to_owned();
    Builder {
        func: move || hello,
    }
}

impl<F: FnOnce() -> String> Builder<F> {
    fn build(self) -> String {
        (self.func)()
    }
}

fn main() {
    let builder = new_builder();
    println!("{}", builder.build());
}

这意味着:“这是编译器会发现的一些未指定类型。这种类型实现 fnonce( ) - &gt; string “。

然后,使用 new_builder 的其他功能将能够访问 func 作为 fnonce() - &gt;字符串对象。

另请注意,我必须将类型更改为 fnonce ,因为 func 在您的情况下会消耗 hello ,因此仅一次可呼应一次。

不用担心。 impl&lt; f:fnonce() - &gt;字符串&gt; 还包括 fn fnmut ,因为它们也被隐含了 fnonce

The main problem here is that the type of a closure cannot be written out in code.

Luckily, for exactly that reason, the impl keyword exists for return types:

struct Builder<F> {
    func: F,
}

fn new_builder() -> Builder<impl FnOnce() -> String> {
    let hello = "hello".to_owned();
    Builder {
        func: move || hello,
    }
}

impl<F: FnOnce() -> String> Builder<F> {
    fn build(self) -> String {
        (self.func)()
    }
}

fn main() {
    let builder = new_builder();
    println!("{}", builder.build());
}

Which means: "This is some unspecified type that the compiler will figure out. It's just important that this type implements FnOnce() -> String".

Other functions that use new_builder will then be able to access func as an FnOnce() -> String object.

Also note that I had to change the type to FnOnce because func in your case consumes the hello and is therefore only callable once.

Don't worry, though. impl<F: FnOnce() -> String> also includes Fn and FnMut, as they are also FnOnce implicitely.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文