有人用 goto 语句么?我是用它代替递归

2017-10-24 16:35:17 +08:00
 me15000

//递归
void repeat(c) {

	
		//需要重复的代码
	

		if (xx) {
			 repeat(xx);
		}

}

//goto 代替递归
void repeat(c) {

	loop:
		//需要重复的代码
	

		if (xx) {
			goto loop;
		}

}


        //一个采集程序
        public void Run(string listurl)
        {
            using (var wc = new WebClient())
            {
                loop:

                string html = Encoding.GetEncoding("utf-8").GetString(wc.DownloadData(listurl));
                var doc = new HtmlDocument();
                doc.LoadHtml(html);
                var nodes = doc.DocumentNode.SelectNodes("//ul[@id=\"data_list\"]/li/div/a");
                for (int i = 0; i < nodes.Count; i++)
                {
                    var node = nodes[i];
                    string link = "http://www..cn" + node.Attributes["href"].Value;
                    string title = node.SelectSingleNode("span[@class=\"sTit\"]").InnerText;
                    Save(title, link);
                }
                var nextnode = doc.DocumentNode.SelectSingleNode("//div[@class='page mb clearfixs']/em/following-sibling::a");
                if (nextnode != null)
                {
                    listurl = "http://www..cn" + nextnode.Attributes["href"].Value;
                    goto loop;
                }
            }
        }
10554 次点击
所在节点    分享发现
128 条回复
tabris17
2017-10-24 17:14:29 +08:00
不谈场景就禁用 goto 的都是刷流氓

goto 要比 do { break; } while (false);优雅得多
jasontse
2017-10-24 17:15:33 +08:00
这样写代码的人走夜路要小心
me15000
2017-10-24 17:15:38 +08:00
@SuperMild

说实话,都用过,唯有 goto 好用
me15000
2017-10-24 17:16:44 +08:00
@hackpro 递归 10 万次试试,goto 表示无压力
halfer53
2017-10-24 17:16:54 +08:00
除非是在 C 里面,任何 goto 都应该禁止。在 C 里面,因为 C 这个语言太接近于底层,没有很多高级语言的功能,所以不得不用 goto, 也只有仅有的几个地方可以使用 goto。比如

···
int* ptr1 = malloc(100 * sizeof(int));
if(ptr1 == NULL)
goto err_ret;

int* ptr2 = malloc(200 * sizeof(int));
if(ptr2 == NULL)
goto err_free_ptr1;

int* ptr3 = malloc(300 * sizeof(int));
if(ptr3 == NULL)
goto err_free_ptr2;

/** do staff **/

free(ptr3);
err_free_ptr2:
free(ptr2);
err_free_ptr1:
free(ptr1);
err_ret;
return;
```
pcatzj
2017-10-24 17:17:31 +08:00
@me15000 #17 首先我是翻译楼上的,其次,你说的循环都能做到,没发现什么必用 goto 的理由,而且 goto 容易打乱别人读代码的节奏。没必要的话,最好不要乱跳代码,功能相同的代码应该聚集。
me15000
2017-10-24 17:17:36 +08:00
@hackpro 其实没懂你说的那种状况,我之前遇到递归到一定数量之后,内存溢出
me15000
2017-10-24 17:20:37 +08:00
@halfer53 其它语言既然提供这个语法,我觉得还是有用它的时候,我一般情况下只在一个 方法体内使用,目前没发现什么不好,估计哪天我写这样的代码,在一个技术型的公司里面该有一大波人吐槽我了,
其实他们也没认真思考过这个问题,没有实践
scys
2017-10-24 17:21:54 +08:00
慎用,加注释。
viator42
2017-10-24 17:24:27 +08:00
不建议用又不是不能用
tabris17
2017-10-24 17:25:52 +08:00
几种可以使用 goto 的场景

1、跳出多层循环

2、return 前的收尾工作( try …… finally ……)

3、异常处理(try …… catch ……)



至于递归,大多数语言是有尾递归优化的,可以避免栈溢出。一般可以转换成 goto 的递归都可以写成尾递归形式。

当然,LZ 说的场景并不适合用 goto
hxsf
2017-10-24 17:30:42 +08:00
goto 可以代替流程控制语句

你举的例子中不用 goto,也可以用 for,while 之类,

递归能解开到循环的,可以用 goto 代替

有的递归不能解开到循环

比如:
void ack(x) {
if (x <=2) return 1;
return ack(x-1) + ack(x-2)
}

上面这个,用循环的话得打表做, 仅仅是举个例子。
wfd0807
2017-10-24 17:45:42 +08:00
楼主这段代码的场景,可以用循环实现,也可以用递归实现;但是群主用了 goto 实现以后,硬说是代替了递归,这就是不太合适了;
lightening
2017-10-24 17:48:32 +08:00
Goto 有两个问题。

第一是,如果你再加上一个跳出循环的判断,就有两个 Goto。那么读代码的人必须上下翻阅代码,找你的标记名字。如果有多个标记,还可能会冲突。

第二个问题其实更重要,就是 Goto 不能显示你的意图。循环有很多种方式,大多数语言都有 for 循环和 while 循环。现代的语言很多又有 forEach。既然所有的功能都能用 while 实现,为什么还要 for 和 forEach ?就是因为这些语法是你思维方式的直接映射。因为人的大脑容量有限,所以我们只能把细节封装起来,从更高的层次抽象思维。一个好的程序要尽量分层描述“你想要什么”而不是“具体怎么做”。如果你想做的是重复一件事直到条件满足,那么 while 最合适了。如果你想做的是一件事几次,那么 for 循环最适合你了。很多人想对一个数组的每一个元素做某种操作,所以就有了 forEach。Goto 却无法表现出你的意图。读代码的人必须读完所有代码,才能琢磨到你想做什么;而不像其他三种循环操作,看一眼框架,虽然不知道你在循环内做了什么,但知道了你是做一个条件循环,还是一定次数的循环,还是对某个数组的每一个元素做了个操作。
facetest
2017-10-24 17:50:31 +08:00
说 goto 不好的,怕是被国内程序设计语言课程给洗脑了,去看看 linux 内核或者 nginx 源码就知道用得有多广泛。
me15000
2017-10-24 17:52:56 +08:00
@wfd0807 不假思索和尝试,不具备发言权,剥夺你发言权利 ^_^,目前我用得很爽
hjc4869
2017-10-24 18:07:27 +08:00
@me15000 我可没跟你说不能用,而是说你这个情况显然有更好的 solution,你应该多思考而不是一把梭怎么爽怎么写
me15000
2017-10-24 18:12:09 +08:00
@lightening VS F12 表示很方便

icyalala
2017-10-24 18:26:54 +08:00
代码是写给人看的。

你的代码如果只写给你自己一个人看,那你自己看懂就可以,随便写没问题。
如果你的代码需要给别人看,除非有特殊理由,那就不要用“将会看你代码的人”普遍厌烦、普遍反对、额外增加他人思考时间才能读懂的方式来写。

linux 内核、nginx 源码这些地方,goto 用得的不少,goto fail、goto cleanup 这类的用法很常见,也很清晰,这类开发者也常常接触这类代码,少有错误的使用方式。用 goto 没什么问题。

你要说 .Net 。。
JamesMackerel
2017-10-24 19:11:01 +08:00
阁下的这种递归写法叫作“尾递归[1]”。

所有的尾递归都可以被转换成循环,事实上,现代的很多编译器都会优化尾递归,使其变为循环来提高程序的执行效率,并减少内存的占用。

GCC 在开启 O2 优化选项时会优化尾递归[2]。不过 Python 和 Java 似乎没有实现尾递归优化[3]。

[1]: https://zh.wikipedia.org/zh-cn/%E5%B0%BE%E8%B0%83%E7%94%A8
[2]: https://zhihu.com/question/20761771/answer/19201814
[3]: https://zhihu.com/question/20761771/answer/92233964

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/400286

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX