Rust中的部分应用程序是否有开销?

时间:2017-10-03 16:10:09

标签: rust closures

我喜欢使用部分应用程序,因为它允许(除其他外)分割复杂的函数调用,这更具可读性。

部分申请的一个例子:

fn add(x: i32, y: i32) -> i32 {
    x + y
}

fn main() {
    let add7 = |x| add(7, x);

    println!("{}", add7(35));
}

这种做法有开销吗?

这是我喜欢做的事情(来自真实的代码):

fn foo(n: u32, things: Vec<Things>) {
    let create_new_multiplier = |thing| ThingMultiplier::new(thing, n); // ThingMultiplier is an Iterator
    let new_things = things.clone().into_iter().flat_map(create_new_multiplier);

    things.extend(new_things);
}

这纯粹是视觉上的。我不喜欢把这些东西叠得太多。

2 个答案:

答案 0 :(得分:4)

在您的特定示例中,是的,extend可以作为循环内联,包含flat_map的另一个循环,而ThingMultiplier又将n实例放入保持thing的相同堆栈槽中和clone

但是你在这里咆哮错误的效率树。而不是想知道一个包含两个字段的小结构的分配是否得到优化,你应该想知道device = AVCaptureDevice.default(for: AVMediaType.video) 的效率是多少,特别是对于大输入。

答案 1 :(得分:4)

在使用之前定义闭包与定义和直接使用闭包之间不应存在性能的区别。存在类型系统差异 - the compiler doesn't fully know how to infer types in a closure that isn't immediately called

在代码中:

let create_new_multiplier = |thing| ThingMultiplier::new(thing, n);
things.clone().into_iter().flat_map(create_new_multiplier)

完全相同
things.clone().into_iter().flat_map(|thing| { 
    ThingMultiplier::new(thing, n)
})

通常,使用闭包不应该有性能成本。这就是Rust所说的“零成本抽象”:程序员自己也不能写得更好。

编译器converts a closure into implementations of the Fn* traits on an anonymous struct。此时,所有正常的编译器优化都会启动。由于单态化等技术,它甚至可能更快。这确实意味着您需要进行常规分析以确定它们是否是瓶颈。