我想计算const
的阶乘。我想最终得到这样的东西:
const N: usize = 4;
const N_PERMUTATIONS = factorial(N);
明显的解决方案(不起作用)是:
const fn
- const fn
中不允许(或至少未实现)条件语句,以下都不会编译:
const fn factorial(n: usize) -> usize {
match n {
0 => 1,
_ => n * factorial(n-1)
}
}
const fn factorial(n: usize) -> usize {
if n == 0 {
1
} else {
n * factorial(n-1)
}
}
宏 - 在所有宏扩展之后执行表达式的评估。此宏永远不会达到基本情况,因为在四次迭代后,参数为4-1-1-1-1
,与0
不匹配:
macro_rules!factorial {
(0) => (1);
($n:expr) => ($n * factorial($n-1));
}
我还尝试了以下内容,如果*
进行了短路评估,它会起作用,但是as-is有无条件的递归会导致堆栈溢出:
const fn factorial(n: usize) -> usize {
((n == 0) as usize) + ((n != 0) as usize) * n * factorial(n-1)
}
(正如Matthieu M.指出的那样,我们可以通过factorial(n - ((n != 0) as usize))
来避免下溢。)
现在我已经使用手动计算阶乘。
答案 0 :(得分:3)
This is currently explored under the feature const_fn
, but for now you cannot call a function, even const, from another const function.
You can however break out the big guns: metaprogramming (procedural macro) to compute the value at compile-time. I found this crate for example (but did not test it, though).
This Rosetta Code page on compile time calculation shows that the compiler can do some compile-time optimization, but nothing is guaranteed, and this is only a particular case.
答案 1 :(得分:2)
自您的原始问题以来,Rust已更新,现在支持const fn
中的条件,因此前两个解决方案都可以使用。参见the docs
指出您可以在const函数中拥有“对其他安全const函数的调用(无论是通过函数调用还是方法调用)”。
对于您的特定阶乘示例,您(至少)有几个选择。这是我已经成功编译的阶乘函数:
const fn factorial(n: u64) -> u64 {
match n {
0u64 | 1u64 => 1,
2u64..=20u64 => factorial(n - 1u64) * n,
_ => 0,
}
}
注意,n!其中n> 20将使{{1}}溢出,因此我决定在这种情况下返回0。另外,由于u64
可以是32位值,因此在这种情况下,我明确使用64位usize
。处理u64
溢出情况还可以防止堆栈溢出。这可能会返回u64
:
Option<u64>
在我的情况下,返回const fn factorial(n: u64) -> Option<u64> {
match n {
0u64 | 1u64 => Some(1),
2u64..=20u64 => match factorial(n - 1u64) {
Some(x) => Some(n * x),
None => None,
},
_ => None,
}
}
限制了我使用该函数的方式,因此我发现仅返回一个{0}与Option<u64>
类似的u64
更为有用。 / p>