有人用 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;
                }
            }
        }
10890 次点击
所在节点    分享发现
128 条回复
msg7086
2017-10-25 11:25:39 +08:00
public void Run(string url)
{
  using (var wc = new WebClient())
 {
   while (url != null)
  {
    string html = Encoding.GetEncoding("utf-8").GetString(wc.DownloadData(url));
    var doc = new HtmlDocument(html);
    url = doc.DocumentNode.SelectSingleNode("//div[@class='page mb clearfixs']/em/following-sibling::a")?.Attributes["href"]?.Value;
  }
 }
}

public void RunMulti(string url)
{
  var urls = new Queue<string>();
  urls.Enqueue(url)
  using (var wc = new WebClient())
 {
   while (urls.Count > 0)
  {
    url = urls.Dequeue();
    string html = Encoding.GetEncoding("utf-8").GetString(wc.DownloadData(url));
    var doc = new HtmlDocument(html);
    Foreach(var node in doc.DocumentNode.SelectNodes("//div[@class='page mb clearfixs']/em/following-sibling::a"))
   {
     urls.Enqueue(node.Attributes["href"]?.Value;
   }
  }
 }
}

没有 VS,随便开了个编辑器手打的,而且 C#大概五六年没写了,如果有错请见谅。

另外,你知道 Encoding.UTF8 吗?
me15000
2017-10-25 11:59:57 +08:00
@msg7086 看见你这种人就烦 Encoding.UTF8, Encoding.GetEncoding("utf-8"),我预留用来动态变换编码你个 xx
me15000
2017-10-25 12:08:19 +08:00
@msg7086

说实话过于技术的人真的很 XX 无力吐槽,在你们这种公司上班肯定很遭罪
100 种实现方法,都可以有,谁 tm 规定必须要你这样写,你规定的,你是法律,和法西斯没啥区别
技术本身服务于需求,能达到目的就好,
曾经有个公司花三年时间做一款产品,技术倒是做到位了,很好很牛逼,结果 tmd 资金没跟上倒闭了
问倒闭原因,就是他们的 XX 技术主管过于技术过度技术,
不懂的不同的时期量力而行,最终项目惨败,不同的项目对技术要求也不一样

我就要一个留言板,够 100 个人用就行了,非要设计成 12306 的技术架构,我也是醉了
这种人哪个公司用,哪个公司倒霉
bumz
2017-10-25 12:17:10 +08:00
goto 不能代替递归。

goto + 栈可以。

goto 不加栈就可以实现的递归代码,本身就用不着递归。

ALGOL 58 引入 for 语句就是为了解决 goto 带来的麻烦,奈何 59 年后又有程序员用 goto 重新定义了循环,还贴上了实用主义的标签。

我们只能说,你高兴就好。

已添加到 V2EX_RECOMMENDED_BLACK_LIST。
noli
2017-10-25 12:46:39 +08:00
@geelaw

https://stackoverflow.com/questions/3179936/goto-out-of-a-block-do-destructors-get-called

C++ 语义上保证 goto 语句, 对作用域内的对象生命周期是安全的。

然而编译器的行为和直观上的感觉可能会不同;
而 break continue 之类的就不会有这样的担忧,因为它们一次只会跳出一个 block。
geelaw
2017-10-25 12:58:08 +08:00
@noli 完了,我觉得这个行为很直观
sagaxu
2017-10-25 13:03:02 +08:00
block++
noli
2017-10-25 14:53:28 +08:00
@geelaw 很直观? 我给你找个实际例子,这段代码会泄露资源,资源类为 TypeA TypeB TypeC


```
std::shared_ptr<TypeA> a(new TypeA);
{
bool error = doA(a);
if (error)
goto out_a;
else
{
std::shared_ptr<TypeB> b(new TypeB);

TypeD d;

error = doB(b, &d);
if (error)
goto out_b;
else
{
std::shared_ptr<TypeC> c(new TypeC);

error = doABC(a, b, c);
if (error)
goto out_c;
else
goto out;
}
}
}

out_c:
undo C

out_b:
undo B:

out_a:
undo A

out:
return ret;

```

确实很直观吧。

要不你建议,试试用 try ? XD XD

try + goto 死得更快
geelaw
2017-10-25 15:40:13 +08:00
@noli 我没有看出这段代码会泄露资源。实际上我也测试了全部 4 种情况,都不会泄露资源。您可能学了假的 C++。
noli
2017-10-25 15:57:51 +08:00
@geelaw 能介绍一下你是怎么测的吗?
geelaw
2017-10-25 16:05:37 +08:00
@noli http://codepad.org/MuZyhWWw

无论输入 0、10、110、111,输出都是配对的。
neoblackcap
2017-10-25 16:23:10 +08:00
C#递归性能很差吗?但是你可以写成尾递归的形式啊,C#有尾递归优化的,不用自己用 goto 来搞
noli
2017-10-25 16:59:15 +08:00
@geelaw 是我复制错代码了,给的是已经修改过后的。

本来应该是把 else 以及后面的 {} 都去掉,至少让你品尝一下 cross initialization 的。
geelaw
2017-10-25 17:14:45 +08:00
@noli 完全去掉 else (以及它产生的作用域),会导致代码是错误的,而不是正确且产生令人惊奇的结果的。
msg7086
2017-10-25 17:29:08 +08:00
@me15000 我们公司成立了差不多 10 年了。
10 年里几乎每一个程序员都得过且过,坏的代码不修,新写的代码稀烂,没有任何代码审核,连 Git 都不会用,要我手把手教。
结果呢?投资的 1500 万美金烧完了,程序连稳定跑都跑不起来,一崩溃就得抹掉数据库重新做,因为连原来设计系统的程序员都不知道哪些行哪些字段里应该填什么,索性全抹了重新初始化。10 万刀一套软件卖给客户,客户三天两头过来骂娘问为什么又崩溃了,为什么一个 UI 界面刷新一下要 15 分钟。然后我们的客服也来骂开发团队,为什么远程客户机器刷一个页面要 15 分钟才能刷完。

我进了公司以后我怂恿老大把他们全开了,现在从上到下所有人全走了,只剩我和一个客服两个人写代码,半年做完基本功能,给 CEO 演示的时候 CEO 已经要哭了。


何况你这代码说白了只是个广度优先搜索,说得难听点我初三就会写了,你偏要当成是多么高深的技术,我只能说我们根本就不是一路人。你心里想的是哇还有 goto 这东西,而我心里想的是公司这卖几十万一套的软件怎么做到不崩溃怎么找到更多客户拉到更多投资最后怎么上市然后我可以捞一票。

不过度追求技术是应该的,作为程序员应该也学过这句话,叫过早的优化是罪恶的根源。
但是连大学本科基本算法都不懂的,贵司还是留着自己享受吧,我们已经用了好多年这样的人了,再用下去,这公司怕是要上天了。

如果你看不惯做技术的,那把我 Block 了便是。只不过这帖子除开你的 goto,剩下的内容营养价值还挺高的,JIT,尾递归优化什么的,如果你能更虚心些去学习他们提到的知识点的话,也算是能提高下自己的姿势水平,这帖子也算没白开。

就这样吧,你自便了。
noli
2017-10-25 17:30:00 +08:00
@geelaw

是否错误,取决于你用哪个编译器,以及 flag。
而且这里也涉及到了 C 和 C++ 的差异,如果有 C 和 C++ 混用的话,效果更显著。

算了,反正你觉得 开心就好。
noli
2017-10-25 17:36:46 +08:00
@geelaw 还是再补充一句。

即使是 C++ 里面,去掉大括号去掉 else
TypeD d; 这一句也并不一定就会编译错误。

视乎你的 TypeD 怎么写。

所以这种一不留神就会踩坑的代码,我真的不觉得直观。

我保留我的意见。
geelaw
2017-10-25 18:06:38 +08:00
@noli non-trivial 构造被跳过本来就是 ill-formed,这样 argue 跟写 i+++i++ 也能编译是一样的。
noli
2017-10-25 18:19:05 +08:00
@geelaw

所以不用 goto 就没有这种连声明个指针 都是 ill-formed 的破事儿
就跟不要写 i+++i++ 这种破代码是一样的道理。
geelaw
2017-10-25 23:07:37 +08:00
@noli 声明的并不是指针而是对象啊……你在想啥?

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

https://tanronggui.xyz/t/400286

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

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

© 2021 V2EX