C# 跳转语句全面演练(第二部分)- goto
介绍
这是C# 跳转语句系列文章的第二部分。在第一部分中,我们深入研究了break和continue语句以及它们在嵌套循环中的工作方式。如果您错过了,请查看。
在本指南中,我们将重点介绍另一个重要的跳转语句:goto语句。我们将讨论使用范围并指出goto的副作用。然后我们将提到其他跳转语句。
作为 C# 流程控制的最后一篇指南,我们将总结迭代、条件和跳转语句之间的关系。
作为初学者的教程,我尽力使用生动的可视化和示例来帮助您理解。
- 首先,我将从一个有趣的场景开始。
- 接下来我会把各类跳转语句的代码模板和流程图展示给大家。
- 此外,我们对其进行了比较,并总结了最佳实践。
- 最后我们来说一下高级用法。
goto 语句
goto是一个功能强大的跳转语句。它可以跳转到同一操作范围内的任意位置。您可以使用goto自定义逻辑流程,甚至可以用它来模拟递归、迭代和选择。
句法
在 C# 中有两种使用goto 的方法:
- switch中的goto:这是 C# switch 中非空 case 转到另一个 case 的唯一方法。
- goto with label: 首先我们用label_name: statement;标记一个语句,然后我们可以通过label_name转到这个语句。注意 label 应该在同一个动作范围内定义。
转到 switch 中
让我们用以下勤奋的程序员示例来练习switch中的goto :
string state = "hungry";
switch (state)
{
case "normal":
Console.WriteLine("coding..");
goto default; // jump to default branch
case "hungry":
Console.WriteLine("eat some stuff");
goto case "normal"; // jump to "normal" branch
case "illness":
Console.WriteLine("see a doctor");
break;
default:
Console.WriteLine("go to sleep");
break;
}
如果状态为“饥饿”,则首先处理“饥饿”案例逻辑,然后跳转到“正常”分支,最后进入默认值。
eat some stuff
coding..
go to sleep
带标签的转接
对于带标签的goto,最适合的用法是在多重嵌套循环或条件中跳转。
我们知道在嵌套循环中break只能作用于当前循环,一个直接的想法就是用一个 flag 来标记状态,然后在外层循环中处理。
这是带有标志的嵌套循环的版本:
int[,,] arr = new int[2, 3, 2] {
{ { 1, 2 }, { 3, 4 }, { 5, 6 } },
{ { 7, 8 }, { 9, 10 }, { 11, 12 } } };
bool flag = false;
for (int i = 0; i < arr.GetLength(0); ++i)
{
for (int j = 0; j < arr.GetLength(1); ++j)
{
for (int k = 0; k < arr.GetLength(2); ++k)
{
if (arr[i, j, k] == 7)
{
flag = true;
break;
}
Console.WriteLine("current element is {0}", arr[i, j, k]);
}
if (flag)
break;
}
if (flag)
break;
}
Console.WriteLine("break multiple loops when value is 7");
这是带有goto 的版本:
for (int i = 0; i < arr.GetLength(0); ++i)
{
for (int j = 0; j < arr.GetLength(1); ++j)
{
for (int k = 0; k < arr.GetLength(2); ++k)
{
if (arr[i, j, k] == 7)
goto Finish;
Console.WriteLine("current element is {0}", arr[i, j, k]);
}
}
}
Finish: Console.WriteLine("break multiple loops when value is 7");
非常简洁、优雅,对吧?
其他用途
除了以上两种主要用途外,这里还有一些其他用途。
我们可以将goto看作是定制我们的控制流的方式,例如模拟递归,迭代和选择。
我们以 do-while 为例,说明如何使用goto进行模拟:
// do-while template
do
{
code_block;
} while (condition);
// rewritten by goto
Loop: code_block;
if (condition)
goto Loop;
这是Python 中的for-else语句。如果没有从循环中break ,它将执行else部分。
for x in range(5):
if x == 3:
print("find 3 in loop")
break
else:
print("not find 3 in loop") # reach there when not break
C# 不支持else ,但是我们可以通过goto轻松实现。
for (int i = 0; i < 5; ++i)
{
if (i == 3)
{
Console.WriteLine("find 3 in loop");
goto Finish;
}
}
Console.WriteLine("not find 3 in loop");
Finish: Console.WriteLine("end of loop");
但是这些用法并不推荐。我们稍后会讨论goto的副作用。
副作用
goto一经发明,争论就从未停止。我引用了wiki goto上的著名观点:
对 GOTO 最著名的批评可能是Edsger Dijkstra于 1968 年写的一封信,题为《Go To 语句被认为有害》。在那封信中,Dijkstra 认为应该从高级语言中废除不受限制的 GOTO 语句,因为它们使分析和验证程序(尤其是涉及循环的程序)正确性的任务变得复杂。Donald Knuth的《使用 go to 语句进行结构化编程》提出了另一种观点,该书分析了许多常见的编程任务,并发现在其中一些任务中,GOTO 是最佳的语言结构。
下面是goto的一个反面例子,其中的代码杂乱无章:
// negative example of goto, tangled code
int x = 0;
Label1: x += 1;
if (x % 2 == 0)
goto Label1;
if (x % 3 == 0)
goto Label2;
Console.WriteLine(x);
Label2: if (x < 10)
goto Label1;
可读性很差。结构很弱,很难调试或维护。
我的建议是:
在现代语言中,goto 有很多替代品,比如上下文管理器、设计模式和其他控制流方法。除了在 switch 和嵌套循环中使用外,我们应该尽量避免使用 goto。
其他跳转语句
还有其他的跳转语句,但是它们适用于特定的情况。
- return语句终止其出现的方法的执行并将控制权返回给调用方法。
- <a href="https://t
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~