递归
写一个名为 down、接受一个名为 n 的 int 的方法。若 n 为 0 或更小,用裸的 return; 停下。否则写出 n,再从同一方法内部调用 down(n - 1)。从 Main 调用 down(3);。屏幕应显示三行:3,然后 2,然后 1。方法不断用更小的数调用自身,直到停止结束整条链。带停止的自调用,就是本页要教的内容。请保留公共类名 Pine。
调用自身的方法
在作用域页上,mark 运行一次就结束了。这里 down 先运行,再在第一次调用尚未完全结束前,用新的实参启动另一次 down。每次调用都有自己的 n。只有某次调用撞上停止时,链才会结束。
打开 Pine 文件。类名保持 Pine。本页不重命名类型。若你仍只有 mark 演示,且那就是 Main 里的全部内容,删掉它。删掉任何残留的 paint。删掉任何 ReadLine 行。你保留的文件不等待键入。
在 Main 之外、仍在类的花括号内,写下 static void down(int n)。本页保持 void:每一步只写出,不需要通过带类型的 return 交回值。停止用无值的 return;——它只结束这一次调用。运行前先保存文件。完整的第一个程序在下一个代码框里。
你保留的文件
这是你首先运行的版本。Main 持有一次调用。down 持有停止、写出行和自调用。
using System;
public class Pine
{
public static void Main()
{
down(3);
}
static void down(int n)
{
if (n <= 0)
{
return;
}
Console.WriteLine(n);
down(n - 1);
}
}
从顶部读起。using System; 准备短名称。public class Pine 给类型命名。public static void Main() 是运行时开始的地方。调用 down(3) 进入时 n 等于 3。它大于 0,所以方法写出 3,再调用 down(2)。第二次调用写出 2,再调用 down(1)。第三次调用写出 1,再调用 down(0)。带 0 的调用撞上 n <= 0,不写出就返回。链结束。屏幕上三行:3,然后 2,然后 1。
用 dotnet run 运行。程序写出三行后停止。它不等你键入。若 dotnet run 在等待,文件里仍有 ReadLine。删掉那一行,保留 down(3); 以及上面的 down 方法。屏幕显示 3,然后 2,然后 1。若屏幕只显示 4,残留的 mark(4) 调用仍在运行。若屏幕显示字母 down,写出行带了引号:Console.WriteLine("down");。屏幕行不对时,不要重装 .NET SDK。
按顺序走完一次完整运行。C# 从 Main 开始。调用 down(3) 进入时 n 等于 3。它大于 0,所以方法写出 3,再调用 down(2)。第二次调用写出 2,再调用 down(1)。第三次调用写出 1,再调用 down(0)。带 0 的调用撞上 n <= 0,不写出就返回。链结束。屏幕保留写出的三行。
每一次调用都是同一段方法文本的一次单独经过。第一次经过在启动 down(2) 之后仍有工作等待——即内层调用返回后再收尾。你不会写四个不同的方法名。你写一个方法,让更小的实参把进度带到停止。
若把起点改成 down(2);,屏幕应显示 2 然后 1。方法体不变;只改第一个实参,所以链更短。从 down(4); 开始应显示四行:4、3、2、1。方法体仍不变;只是 Main 挑选第一个值。
把停止放在最前
停止必须在写出行和自调用之前检查。若先写出却从不测 n,或总是用同一值调用 down(n),程序就不会结束。在本页的初学者形状里,把 if (n <= 0) 块放在方法顶部。
using System;
public class Pine
{
public static void Main()
{
down(2);
}
static void down(int n)
{
if (n <= 0)
{
return;
}
Console.WriteLine(n);
down(n - 1);
}
}
这是第二个文件。它用更短的起点教同一方法体。运行 dotnet run。屏幕显示 2 然后 1。当 n 到达 0 时,停止仍会结束链。写成 down(n) 而不是 down(n - 1),会一遍又一遍送出同一个数。那时程序可能一直跑到系统打断它。更小的实参是思路的一部分:每次调用都必须朝停止移动。
把停止想成出口门。写出行是本步要做的事。自调用是下一步。若没有门,每一步都会无尽地再开一步。若下一步仍用同一个 n,你永远走不到门口。两种错误在源码里看起来不同,但在本页的初学者形状里都拒绝干净结束。看到 2 然后 1 之后,若你想保留的形状是 down(3),就把保留文件放回去。
调用链与屏幕对照
把一次起始调用和它产生的屏幕行放在一起读。每一行表格是一次仍会写出的 down 造访。
📊 down call chain for down(3)
| Call | Value of n | Screen line |
|---|---|---|
first down(3) |
3 |
3 |
then down(2) |
2 |
2 |
then down(1) |
1 |
1 |
then down(0) |
0 |
(no line — stop) |
常见混淆是漏掉停止。那样每次调用都会写出并永远再调用。另一种混淆是把写出放在递归调用之后而不是之前。本页写出行在前,所以屏幕倒着数。若把 Console.WriteLine 移到 down(n - 1) 下面,行的顺序会变——为了这里展示的倒计时,请把写出行保持在自调用之上。
上一页的作用域仍有一点关系:每次调用的 n 是那次调用自己的参数。外层调用的 n 不会在内层运行时改写自己。内层有单独的 n。内层返回后,外层从自调用之后的那一行继续——而本页那里就是方法的结尾。
残留的 mark 演示可能留在同一文件里;若 Main 仍调用 mark,屏幕就会乱。学本页时把 Main 清到只剩 down(3); 或 down(2);。不要把 down 嵌进 Main 的花括号里。方法放在类里,与 Main 并列。
在 Main 里写 Console.WriteLine("down"); 会写出单词 down。它不会启动链。若要三行倒计时,请保留 down(3);。
另一种形状:停止什么也不写
你已经见过带 0 的调用会安静返回。也可以练习起点值为 1。屏幕应显示一行:1。下一次调用是停下的 down(0)。
using System;
public class Pine
{
public static void Main()
{
down(1);
}
static void down(int n)
{
if (n <= 0)
{
return;
}
Console.WriteLine(n);
down(n - 1);
}
}
这是第三个文件。运行 dotnet run。屏幕显示一行:1。同一方法体覆盖 down(3)、down(2) 和 down(1)。只改 Main 里的第一个实参。对本页的初学者内容已经够了。从递归返回总和这类更深的想法留给后续课程;这里的目标是自调用、更小的实参和停止。
若屏幕什么也不显示,检查 Main 是否仍在调用别的东西,或停止测试是否写错——例如 if (n >= 0) 在你用正数 n 起步时,会在任何写出之前就停下。把 n <= 0 当作安静出口,并在 Main 里保留正数起点,这样至少能出现一行。
你可以写 down(int n),在 n 为 0 或更小时停下,写出 n,再调用 down(n - 1)。从 Main 一次调用启动整条链。屏幕显示倒计时各行。从不朝停止移动的方法不会结束。下一页是 classes,你将在那里开始构建带字段的类型,超出这些 static 方法页。
屏幕保留倒计时
你保留的文件在 Main 调用 down(3); 时写出 3,然后 2,然后 1。自调用在 down 内部;除非你给字母加了引号,否则屏幕上不会把 down 当作打印出来的标签。把 down 嵌进 Main 不是本课要建的形状。
🧠 测试您的知识
测试您的知识
通过这个互动测验挑战自己,看看你对这个主题的理解程度如何
📝 说明
- 仔细阅读每个问题
- 为每个问题选择最佳答案
- 您可以随时重新参加测验
- 您的进度将显示在顶部