2 个版本

0.1.1 2024年4月8日
0.1.0 2024年3月28日

#292算法

Download history 6101/week @ 2024-04-22 5470/week @ 2024-04-29 7030/week @ 2024-05-06 9754/week @ 2024-05-13 11031/week @ 2024-05-20 12988/week @ 2024-05-27 12925/week @ 2024-06-03 12273/week @ 2024-06-10 14021/week @ 2024-06-17 15628/week @ 2024-06-24 14664/week @ 2024-07-01 12056/week @ 2024-07-08 12138/week @ 2024-07-15 13214/week @ 2024-07-22 14730/week @ 2024-07-29 12907/week @ 2024-08-05

53,828 每月下载量
用于 67 个 crate (3 个直接使用)

MIT 许可证

6KB

Recursive

使用 recursive,您可以轻松创建(间接)递归函数,而无需担心栈溢出,只需将它们标记为 #[recursive]

use recursive::recursive;

#[recursive]
fn sum(nums: &[u64]) -> u64 {
    if let Some((head, tail)) = nums.split_first() {
        head + sum(tail)
    } else {
        0
    }
}

带有 #[recursive] 的函数将在调用时如果栈空间太小则会自动增长栈空间。有关详细信息,请参阅 crate 文档

许可证

recursive 使用 MIT 许可证。


lib.rs:

Rust 与递归函数的关系存在问题,因为递归深度大的函数可能会造成栈溢出,导致程序崩溃。这个 crate 通过标记(间接)递归函数作为此类函数来轻松解决这个问题

use recursive::recursive;

#[recursive]
fn sum(nums: &[u64]) -> u64 {
    if let Some((head, tail)) = nums.split_first() {
        head + sum(tail)
    } else {
        0
    }
}

它通过在每个函数调用开始时检查剩余栈空间的大小来防止栈溢出。如果这个大小低于由 set_minimum_stack_size (默认为 128 KiB)设置的边界,则会分配一个新的栈,并在该栈上继续执行。这个新栈的大小使用 set_stack_allocation_size 设置,默认为 2 MiB。

这个 crate 通过在您的函数体中调用 stacker::maybe_grow 来工作。如果这个 crate 对于您的需求来说不够灵活,可以考虑直接使用 stacker

有什么缺点吗?

这个 crate 不是零成本的,但它也不限于简单的尾递归或直接递归。然而,在大多数情况下,栈大小测试非常快,几乎总是成功而无需分配。如果您的递归算法对性能非常敏感,我建议无论如何都重写为迭代版本。

该软件包仅支持那些由stacker支持的平台。Rust编译器本身也使用stacker,因此您编译的平台应该总是没有问题,但对于更不常见的目标,请参阅其文档。

我应该将哪些函数标记为#[recursive]

任何直接调用自身的函数都应该标记为#[recursive],除非您确信堆栈足够大,可以处理该函数被调用的任何输入。如果您将不受信任的输入喂入递归函数,您应该始终将其标记为#[recursive]

没有必要将所有可能间接递归的函数都标记为#[recursive]。只要每个可能的函数调用循环至少包含一个标记为#[recursive]的函数,您就可以防止由于递归而导致的堆栈溢出。

依赖关系

~0.4–1.2MB
~25K SLoC