【发布时间】:2016-06-11 22:01:59
【问题描述】:
我想知道为什么我得到 VS/Resharper 的第一种方式注意到尾递归可以用循环替换,而且我确实设法得到类似导致堆栈溢出的东西,所以我阅读了尾递归的方法工作以及它如何增长堆栈等。
第一个生成尾递归注释。
private static string GetLine()
{
string s = Console.ReadLine();
if (s == null)
{
return GetLine();
}
return s;
}
但这样做不会:
private static string GetLine()
{
string s = Console.ReadLine();
if (s == null)
{
s = GetLine();
}
return s;
}
所以我的问题是;第二个不被认为是尾递归的,即它不能创建堆栈溢出,因为它不会生成所有堆栈调用?
【问题讨论】:
-
你倒过来了,尾递归不会产生栈溢出,但是非尾递归调用可以。
-
在任何情况下,C# 都不能保证即使尾调用优化可以完成,它实际上已经完成。所以它无论如何都会造成堆栈溢出(它实际上也会发生,除了有时在 x64 上)
-
@LucasTrzesniewski, naive tail recursion 将 产生堆栈溢出,除非系统中存在(并且被正确使用)运算符来针对该场景进行优化。 CLR 确实有这样的操作码 (
tail)。 C# 没有可靠地利用该操作码的工具。 -
@KirkWoll AFAIK RyuJIT 不需要
tail前缀并生成一个循环(请参阅我的答案),但不能保证,正如 x86 版本所示。 -
@Kirk,C# 本身(即我们)可能没有该车辆,但 编译器 拥有它,并且可以根据其运行的上下文决定使用它。这样实际上更好更安全。
标签: c# .net stack-overflow tail-recursion