将goto语句转换为if、switch、while、break等

4

有没有一种机械化的方法来将goto语句转换成ifswitchwhilebreakcontinue语句,或者使用函数调用、对象等方式?


1
你为什么需要知道这个?这只是一个思想实验还是你有真正的原因在问? - Kip
1
模拟goto应该是不必要的 - 在很少的情况下,使用goto不是设计不良的症状。 - Thomas Owens
7个回答

10

虽然这并不是一个好主意,但可以使用循环和switch-case语句。在下面的例子中,goto变量决定了当遇到continue时跳转到哪个标签(0、1、2或default)。

int goTo=0;
while(true){
  switch(goTo){
  case 0:
    doSomething();
    goTo = 1;
    continue;
  case 1:
    doSomethingElse();
    goTo = 2;
    continue;
  case 2:
    doSOmethingDifferent();
    goTo = 0;
    continue;
  default:
    return;
  }
}

3
其实这个代码块本质上并没有什么不好的想法(虽然我不知道是否会将其用作绕过没有goto的方法)。这只是一个有很多合法目的的有限状态机的基本实现。 - Falaina
在Java中,while循环的条件不能为整数。while(true) - pjp
1
感谢pjp。我真的希望Java能够支持将1作为true,0作为false传递。除此之外,Java真是太棒了。 - Marius
7
在我看来,“0”和“1”不等同于分别表示“false”和“true”是Java中最好的决定之一。;-) - Joachim Sauer

6
我认为这个值得在这里分享。我有一天在Reddit上看到了这个实现,它是通过自定义类加载器将goto实现到任意行号(在同一个.java文件中)。这是一段有趣的代码。http://steike.com/tmp/goto.zip。我不会对此负责。
编辑: 对于那些好奇但不想下载zip并运行的人,以下是该文件:
public class GotoDemo {

    public static void main(String[] args) {
        int i = 5;
        System.out.println(i);
        i = i - 1;
        if (i >= 0) {
            GotoFactory.getSharedInstance().getGoto().go(4);
        }

        try {
            System.out.print("Hell");
            if (Math.random() < 2) throw new Exception();            
            System.out.println("World!");
        } catch (Exception e) {
            System.out.print("o ");
            GotoFactory.getSharedInstance().getGoto().go(13);            
        }
    }
}

它将打印出:
   3
   2
   1
   0
   Hello World!

7
有趣的方式很令人恐惧。 - Joachim Sauer
@JoachimSauer 最可怕的部分是单例模式。 - user1804599

4

考虑到goto语句可能在跳转时引起的复杂性,这是非常可疑的。


1
我认为原问题的意思是:“我正在维护一个应用程序,它在各个地方都使用了goto。我想创建一个应用程序,它将遍历代码并用if、for循环、函数等替换goto以摆脱它们。” 当我试图回答那个问题时,其他人似乎在试图回答“如何制作一个模拟使用goto的开关?” 我认为这不太有用。 - Will Eddins
+1 你和我看到这个问题的方式一样,我基本上同意你的答案。也许有特定的GOTO用法可以自动检测和替换,但在一般情况下可能不可能做到。 - slim
我理解你的意思,但我认为你是错的。开关“solution”可以用于机械地转换包含goto的源代码;除非我漏掉了什么,否则您可以编写脚本以获取任意代码并将其转换。这不是一个好的解决方案,但它有效。 - Alex Feinman
在我脑海中,我正在考虑在一个函数的中间跳转到另一个函数的中间的goto,从而跳过第一个函数末尾和第二个函数开头的代码。我认为switch只有在使用goto在选择之间跳转时才有用,在这种情况下,switch将执行完全相同的操作。我假设这是Java中goto的合法用法,因为我相当确定其他语言也是如此。你可能会想到最好的情况,但我却在考虑最坏的情况。 - Will Eddins
@Guard Java没有goto,因此根据定义,不存在“合法使用goto”!在C中,标签具有函数作用域,因此您无法跳转到另一个函数。然而,像您一样,我也在考虑最坏的情况,即goto将您发送到不同的函数。BBC BASIC允许您这样做,我相信许多其他语言也是如此。 - slim

4
Java语言不支持模拟任意位置的goto语句(甚至不能在同一方法中实现)。您可以使用提到的结构实现一些简单的goto用途,但无法通过这种方式实现所有可能的goto用途。在字节码级别上,您可能可以实现goto(至少在一个方法内),但在这种情况下,该字节码无法映射回有效的Java代码。至于跨越方法或对象边界的goto:这对JVM来说绝对是大忌。整个Java安全模型取决于代码可验证,并且具有仅定义的入口点(也称为“方法”)。免责声明:假定您不想完全重构方法以实现goto效果,这可能还会调用代码复制并混淆方法的“正常”流程。由于您可以在Java方法中实现图灵机,因此您肯定可以在Java方法中实现“goto”;-)

2
当然:(为了更清晰地缩写)
int goTo = 0; boolean done = false;
while (!done) {
  switch (goTo) {
     default:
     case 1: System.out.println("We're at line 1!"); goTo = 2; break;
     case 2: System.out.println("We're going to line 4!"); goTo = 4; break;
     case 3: System.out.println("We're at line 3 and we're done!"); done = true; break;
     case 4: System.out.println("We're at 4, going to 2! Screw you, line 3!"); goTo = 2; break;
  }
}

我不知道你为什么想要这样做,但是嘿,你可以...


1
这几乎与Marius的答案完全相同。正如在那里指出的那样,这是一个有限状态机(即将"goTo"改为"state")。FSM没有问题,但将其用作goto的解决方法会很奇怪。 - Kip
是的,当我在编辑窗口中时他发了帖子...多线程的危险之处...很奇怪,但这回答了OP的要求。 - Alex Feinman

0

是的,使用你提到的方法的组合...是可能的(实际上任何事情都是可能的,只是找出如何正确地做这件事是一件痛苦的事情)。

请记住,goto可能会导致非常复杂的执行路径...因此可能会在生成的任何内容中导致大量不美观的重复代码。


它不一定需要重复,只是需要大量的样板文件。请参见下文。 - Alex Feinman

0
实际上,我认为任何给定的goto示例都可以被翻译成其他东西,特别是如果允许方法提取转换。这是一个抽象的问题还是你真的有很多goto需要一个实际的工具?也许Java代码本身是从某个地方机器翻译过来的?
我曾经在我写的每个程序中放置一个实际的goto,只是为了惹恼那些纯粹主义者。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接