2 个版本
0.1.1 | 2024年4月8日 |
---|---|
0.1.0 | 2024年3月28日 |
#292 在 算法
53,828 每月下载量
用于 67 个 crate (3 个直接使用)
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