【问题标题】:type erasure for functions in rustrust中功能的类型擦除
【发布时间】:2021-04-20 16:02:23
【问题描述】:

考虑一下这个 C++ 代码:

#include <iostream>
#include <functional>

using namespace std;

std::function<int(int, int)> foo(int c) {
  auto add = [] (int a, int b) { return a + b; };
  auto sub = [] (int a, int b) { return a - b; };
  if (c > 42) {
    return add;
  } else {
    return sub;
  }
}

int main() {
  cout << foo(100)(10, 20) << '\n';
}

两个 lambda(add 和 sub)都通过 std::function 进行类型擦除,然后在 main 中调用该函数。 我想知道如何在 rust 中复制这种模式?

【问题讨论】:

  • 我不确定我是否理解“通过std::function 擦除类型”的意思。 add 和 sub 是通用的,但从 foo 返回的 std::function 仅适用于 ints。被擦除的类型是 std::function 中包含的 lambda 的类型,是你的意思吗?
  • @largest_prime_is_463035818 让我稍微澄清一下这个问题。我已经删除了 auto 并明确了类型。是的,这就是我的意思。每个 lambda 都是不同的类型,但是当我们分配给 std::function 时,我们已经有效地删除了该类型。 (std::function 在其实现中通过虚方法实现)

标签: c++ rust


【解决方案1】:

您的示例的一个相当精确的翻译是以下 sn-p。

fn foo(c: i32) -> Box<dyn Fn(i32, i32) -> i32> {
    let add = |a, b| a + b;
    let sub = |a, b| a - b;
    Box::new(if c > 42 { add } else { sub })
}

fn main() {
    println!("{}", foo(100)(10, 20));
}

一种类型的闭包是不可命名的,所以我们将它强制为一个特征对象并将其存储在堆中,据我所知,这与std::function 所做的事情大致相同。

【讨论】:

  • > 与 std::function 的作用相同。正确的。它实现了一个带有调用操作符的虚接口,并保存了基类指针。
  • 我认为std::function 被允许采用小尺寸优化,它将函数存储在自身内部而不是堆分配它。有时很难记住哪些类型由于其他要求而不能进行这样的优化。
  • @chris in rust 您可能会“手动”使用专用枚举,但遗憾的是枚举不会像 Fn (and friends) still can't be implemented in stable 那样成为函数。
  • 请注意,由于闭包实际上并没有借用它们的上下文,您可以使用fn foo(c: i32) -&gt; &amp;'static dyn Fn(i32, i32) -&gt; i32 作为您的签名,避免堆分配。这仍然会擦除类型并动态调度,尽管我们绑定到静态函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多