gpt4 book ai didi

parameters - Rust 标准库闭包参数 : run time or compile time?

转载 作者:行者123 更新时间:2023-11-29 07:56:47 25 4
gpt4 key购买 nike

我正在浏览 Rust标准库。令我震惊的是,当闭包作为参数传递给函数时,它是在运行时传递的。例如来自 Iterator trait :

fn filter<'r>(self, predicate: 'r |&A| -> bool) -> Filter<'r, A, Self>

这里的'predicate'不是泛型参数,而是一个普通的运行时参数。但这是否意味着编译器不能内联对“predicate”的调用?这是故意的设计选择[例如避免代码膨胀]还是 Rust 语言没有提供在编译时传递闭包的方法?

最佳答案

你是正确的,闭包目前是有效的特征对象,也就是说,它们存储了一个指向它们实际代码的函数指针(类似于 C++ 中的 std::function)。

这被认为是不充分的,并且不是最终的设计,实际上当前的工作正在 "unboxed closures" 上进行,它通过使 Rust 的闭包像 C++11 的闭包一样解决这个问题,其中每个闭包都有一个实现适当的唯一类型使其可调用的方法。 (当前的 Rust 提案包含 3 个完全灵活的特征(FnFnMutFnOnce),请参阅上面的 RFC 链接了解更多详情)。

在那之后,filter 可能看起来像

fn filter<'r, F: FnMut<(&A,), bool)>(self, predicate: F) -> Filter<A, Self, F>

(可能有糖分,所以绑定(bind)可以写成 F: |&A| -> bool ,甚至可以写成 more sugar ,这样就可以直接写出类似 predicate: impl |&A| -> bool 的东西,而无需额外的类型参数(尽管这不适用于 .filter ,因为它需要将类型参数传递给返回类型)。)

在这个方案下,通过与 trait 对象工作的完全相同的机制,仍然可以有一个被删除的函数类型(例如停止代码膨胀,或者在某些数据结构中存储许多不同的闭包),编写类似predicate: &mut FnMut<(&A,), bool> ,但这些不会在迭代器适配器中使用。


另外,现在 LLVM 可能内联动态闭包,但这绝对不像静态分发的未装箱闭包那样容易或保证,例如

fn main() {
for _ in range(0, 100).filter(|&x| x % 3 == 0) {
std::io::println("tick") // stop the loop being optimised away
}
}

编译为以下优化的 LLVM IR(通过 rustc --emit=ir -O ):

; Function Attrs: uwtable
define internal void @_ZN4main20h9f09eab975334327eaa4v0.0E() unnamed_addr #0 {
entry-block:
%0 = alloca %str_slice, align 8
%1 = getelementptr inbounds %str_slice* %0, i64 0, i32 0
%2 = getelementptr inbounds %str_slice* %0, i64 0, i32 1
br label %match_else.i

match_else.i: ; preds = %loop_body.i.backedge, %entry-block
%.sroa.012.0.load1624 = phi i64 [ 0, %entry-block ], [ %3, %loop_body.i.backedge ]
%3 = add i64 %.sroa.012.0.load1624, 1
%4 = srem i64 %.sroa.012.0.load1624, 3
%5 = icmp eq i64 %4, 0
br i1 %5, label %match_else, label %loop_body.i.backedge

match_else: ; preds = %match_else.i
store i8* getelementptr inbounds ([4 x i8]* @str1233, i64 0, i64 0), i8** %1, align 8
store i64 4, i64* %2, align 8
call void @_ZN2io5stdio7println20h44016c4e880db7991uk11v0.11.0.preE(%str_slice* noalias nocapture nonnull %0)
br label %loop_body.i.backedge

loop_body.i.backedge: ; preds = %match_else, %match_else.i
%exitcond = icmp eq i64 %3, 100
br i1 %exitcond, label %join4, label %match_else.i

join4: ; preds = %loop_body.i.backedge
ret void
}

特别是,过滤器调用是完全内联的:它都在 match_else.i: block 中,您可以看到 %4 = srem i64 ..., 3 调用是 % 3 代码段,而 icmp eq i64 %4, 0== 0 位。

关于parameters - Rust 标准库闭包参数 : run time or compile time?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24224811/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com