Skip to main content
Sébastien Lorber
Docusaurus maintainer
View all authors

程序结构只有三种

· 3 min read
Sébastien Lorber
Docusaurus maintainer
Yangshun Tay
Ex-Meta Staff Engineer, Co-founder GreatFrontEnd

程序结构只有三种:顺序、分支、循环。这句话正确吗?我认为 break 和 continue 也属于程序结构

这是一个非常经典且深刻的编程理论问题。

直接给结论:从结构化程序设计(Structured Programming)的理论定义来看,你的教材或老师是对的,但你的直觉也反映了现代编程的实际情况。

我们可以从以下两个维度来拆解这个问题:


1. 为什么说“只有三种”?(理论层面)

在计算机科学中,这被称为 Böhm-Jacopini 定理。该定理证明了:任何算法都可以只用这三种基本控制结构来表示。

结构核心逻辑形象比喻
顺序 (Sequence)代码按编写顺序从上到下执行。直行道,没有分叉。
分支 (Selection/Branch)根据条件的真假选择不同的路径(if, switch)。十字路口,根据红绿灯选路。
循环 (Iteration/Loop)重复执行一段代码直到满足退出条件(for, while)。操场跑圈,跑够数为止。

这三种结构之所以被视为“原子级”的基石,是因为它们足以构建任何复杂的逻辑。


2. 为什么 breakcontinue 不算独立结构?(语义层面)

你认为它们属于程序结构是有道理的,因为它们确实改变了程序的流向。但在计算机术语中,它们通常被归类为**“跳转语句”(Jump Statements)**,而不是“结构”。

  • 它们是“附属品”breakcontinue 不能独立存在。如果没有循环(或 switch),它们就失去了存在的意义。
  • 它们的作用是“干预”而非“构建”
    • break 是强制结束当前循环。
    • continue 是跳过本次迭代,直接进入下一次判定。
  • 本质是受限的 goto:在早期的编程中,人们使用 goto 随处跳转,导致代码像“意大利面”一样混乱。为了规范化,现代语言引入了 breakcontinue 作为有纪律的跳转,用来辅助优化循环结构。

3. 你的理解错了吗?

你并没有错,你只是在用“功能角度”看问题,而定理是在用“最小完备集”看问题。

  • 理论上:不需要 break,你也可以通过修改循环条件(比如 while 的布尔值)来实现同样的功能。
  • 实践上:为了让代码更好读、更简洁,我们离不开 breakcontinue

小贴士:在 C# 中,除了这三种基本结构和跳转语句,还有一种特殊的结构叫 异常处理 (Exception Handling),即 try-catch-finally。虽然它本质上也涉及分支和跳转,但在现代应用开发中,它常被视为第四种重要的流控制方式。


总结

“顺序、分支、循环”是构建大厦的砖块、钢筋和水泥;而 breakcontinue 更像是电梯或紧急出口——它们很有用,但你不能只用电梯盖出一栋房子。

既然聊到了跳转,你想看看在嵌套循环中,如何优雅地使用 break 才能避免逻辑混乱吗?

程序结构只有三种

· 3 min read
Sébastien Lorber
Docusaurus maintainer
Yangshun Tay
Ex-Meta Staff Engineer, Co-founder GreatFrontEnd

程序结构只有三种:顺序、分支、循环。这句话正确吗?我认为 break 和 continue 也属于程序结构

这是一个非常经典且深刻的编程理论问题。

直接给结论:从结构化程序设计(Structured Programming)的理论定义来看,你的教材或老师是对的,但你的直觉也反映了现代编程的实际情况。

我们可以从以下两个维度来拆解这个问题:


1. 为什么说“只有三种”?(理论层面)

在计算机科学中,这被称为 Böhm-Jacopini 定理。该定理证明了:任何算法都可以只用这三种基本控制结构来表示。

结构核心逻辑形象比喻
顺序 (Sequence)代码按编写顺序从上到下执行。直行道,没有分叉。
分支 (Selection/Branch)根据条件的真假选择不同的路径(if, switch)。十字路口,根据红绿灯选路。
循环 (Iteration/Loop)重复执行一段代码直到满足退出条件(for, while)。操场跑圈,跑够数为止。

这三种结构之所以被视为“原子级”的基石,是因为它们足以构建任何复杂的逻辑。


2. 为什么 breakcontinue 不算独立结构?(语义层面)

你认为它们属于程序结构是有道理的,因为它们确实改变了程序的流向。但在计算机术语中,它们通常被归类为**“跳转语句”(Jump Statements)**,而不是“结构”。

  • 它们是“附属品”breakcontinue 不能独立存在。如果没有循环(或 switch),它们就失去了存在的意义。
  • 它们的作用是“干预”而非“构建”
    • break 是强制结束当前循环。
    • continue 是跳过本次迭代,直接进入下一次判定。
  • 本质是受限的 goto:在早期的编程中,人们使用 goto 随处跳转,导致代码像“意大利面”一样混乱。为了规范化,现代语言引入了 breakcontinue 作为有纪律的跳转,用来辅助优化循环结构。

3. 你的理解错了吗?

你并没有错,你只是在用“功能角度”看问题,而定理是在用“最小完备集”看问题。

  • 理论上:不需要 break,你也可以通过修改循环条件(比如 while 的布尔值)来实现同样的功能。
  • 实践上:为了让代码更好读、更简洁,我们离不开 breakcontinue

小贴士:在 C# 中,除了这三种基本结构和跳转语句,还有一种特殊的结构叫 异常处理 (Exception Handling),即 try-catch-finally。虽然它本质上也涉及分支和跳转,但在现代应用开发中,它常被视为第四种重要的流控制方式。


总结

“顺序、分支、循环”是构建大厦的砖块、钢筋和水泥;而 breakcontinue 更像是电梯或紧急出口——它们很有用,但你不能只用电梯盖出一栋房子。

既然聊到了跳转,你想看看在嵌套循环中,如何优雅地使用 break 才能避免逻辑混乱吗?

git stash

· 2 min read
Sébastien Lorber
Docusaurus maintainer
Yangshun Tay
Ex-Meta Staff Engineer, Co-founder GreatFrontEnd

情况总结

  • 家里电脑A:更新了远程 dev 分支
  • 单位电脑:直接改了本地 dev,没拉最新代码
  • 现在想:把远程最新的 + 你本地改的 安全合并

正确操作步骤(必看)

第一步:先把你本地修改暂存起来(防止丢失)

打开你的项目 Git 窗口 / 终端

git stash

作用: 把你下午写的代码临时藏起来,不提交,但安全保存。


第二步:拉取远程最新的 dev

git pull origin dev

这一步会把家里早上更新的内容拉到你单位电脑。


第三步:把你刚才藏起来的代码 恢复回来

git stash pop

作用: 自动合并:远程最新 + 你本地修改


第四步:如果没有冲突 → 直接提交

git add .
git commit -m "合并本地与远程dev"
git push origin dev

如果出现冲突(红字)怎么办?

不用慌! Git 会告诉你哪个文件冲突,你打开文件,会看到类似:

<<<<<<< HEAD
家里的代码
=======
你单位写的代码
>>>>>>> stash

你只需要:

  1. 删掉符号 <<<<<=====>>>>>
  2. 保留你想要的代码
  3. 保存文件

然后执行:

git add .
git commit -m "解决合并冲突"
git push origin dev

一句话总结流程(你记这个就行)

藏代码 → 拉最新 → 恢复代码 → 提交推送

git stash
git pull origin dev
git stash pop
git add .
git commit -m "合并"
git push

重要提醒

永远记住: 每次开始写代码前,一定要先 pull 最新代码!


总结

  1. 你现在的情况完全可以安全合并,不会丢代码
  2. stash → pull → pop → commit 顺序操作
  3. 有冲突就手动改,非常安全

First Blog Post

· 4 min read
Sébastien Lorber
Docusaurus maintainer
Yangshun Tay
Ex-Meta Staff Engineer, Co-founder GreatFrontEnd

如果你刚开始学习 C# 和 .NET,一定会频繁遇到一个词——NuGet。它几乎是每个 .NET 项目都离不开的工具。那么,NuGet 究竟是什么?这个奇怪的名字又是怎么来的?这篇文章将一次性讲清楚。


一、NuGet 是什么?

NuGet 是 .NET 平台的包管理器。通俗地说,它就是一个 “代码超市”

在开发软件时,很多常见功能(比如解析 JSON、操作 Excel、连接数据库)其实不需要你从头编写。社区和微软已经提供了大量高质量、经过测试的代码库(称为“包”)。NuGet 的任务就是帮你 找到、下载、安装、更新 这些包,并自动处理它们之间的依赖关系。

NuGet 的核心功能

  1. 安装第三方库
    假设你需要处理 JSON 数据。如果没有 NuGet,你需要去官网下载 Newtonsoft.Json.dll,手动复制到项目文件夹,再添加引用。而有了 NuGet,你只需在 Visual Studio 中打开“管理 NuGet 程序包”,搜索 Newtonsoft.Json,点击“安装”,一切自动完成。

  2. 自动管理依赖
    一个包可能依赖其他包。例如,安装 A 包时,如果它需要 B 包,NuGet 会自动把 B 也下载并配置好,无需你手动干预。

  3. 版本控制
    你可以精确指定要安装的版本(如 1.0.02.0.0)。当包有新版本时,NuGet 会提示你更新,且可以轻松回退。

  4. 统一仓库
    全球的 .NET 开发者都将自己的包发布到 NuGet 官方仓库 nuget.org 上。目前该仓库已拥有超过 30 万个包,总下载量数十亿次。

如何使用 NuGet?

在 Visual Studio 中,最简单的方式是:

  • 右键单击项目 → “管理 NuGet 程序包”
  • 在“浏览”选项卡中搜索你需要的包
  • 选择版本,点击“安装”

如果你习惯命令行,可以在“程序包管理器控制台”或终端中执行:

Install-Package Newtonsoft.Json

对于 .NET Core / .NET 5+ 项目,还可以使用 dotnet 命令:

dotnet add package Newtonsoft.Json

二、“NuGet” 这个名字的来历

“NuGet” 是一个生造的单词,但它背后有一段有趣的故事。

从 NuPack 到 NuGet

NuGet 最初的名字叫 NuPack(New Package 的缩写),意为“新包”。它在 2010 年由微软的团队开发,旨在为 .NET 提供一个官方的包管理工具。

然而,在发布前夕,团队发现 “NuPack” 这个名称与另一款商业产品重名。为了避免商标纠纷,他们不得不紧急改名。

在讨论新名字时,团队成员之一提出了 “NuGet” 的建议。这个名字保留了原名的 “Nu” 前缀,又用 “Get” 替代了 “Pack”

名字的含义

  • Nu = New(新)
    在英语中,“Nu” 是 “New” 的谐音或简写。这体现了包管理器的核心理念:获取“新”的代码组件,同时也象征着 .NET 生态的新生。

  • Get = 获取
    直观地表达了工具的功能——从仓库中获取(Get)包。

因此,“NuGet” 的字面意思就是 “获取新组件”

文化彩蛋:希腊字母 Νυ

也有一种非官方的说法认为,“Nu” 还暗指希腊字母 $\Nu$(Nu)。在科技领域使用希腊字母命名是一种常见做法(如 μTorrent、π 等),这为名字增添了一丝极客色彩。


三、NuGet 对 .NET 开发者的意义

对于 C# 学习者来说,NuGet 可以让你站在巨人的肩膀上。无论是做 Web 开发、桌面应用、移动应用,还是游戏开发,你几乎总能找到一个现成的 NuGet 包来快速实现所需功能。

类比其他语言:

  • JavaScript 世界:npm
  • Python 世界:pip
  • Java 世界:Maven
  • .NET 世界:NuGet

总结

  • NuGet 是什么:.NET 的包管理器,帮你下载、安装、管理第三方代码库。
  • 名字由来:从 “NuPack” 改名而来,“Nu” 代表 “New”,“Get” 代表获取,合起来就是“获取新组件”,简洁地表达了工具的核心功能。

下次当你需要在项目中引用一个第三方库时,记得去 NuGet 超市逛一逛,你会发现那里几乎有你想要的一切。

C#程序的书写规范

· One min read
Sébastien Lorber
Docusaurus maintainer
Yangshun Tay
Ex-Meta Staff Engineer, Co-founder GreatFrontEnd

提高可读性

// 不好的写法
int a=10;int b=20;int c=a+b;Console.WriteLine(c);

// 好的写法
int a = 10;
int b = 20;
int c = a + b;
Console.WriteLine($"计算结果:{c}");

使用空行分组

// 输入部分
Console.Write("请输入姓名:");
string name = Console.ReadLine();

Console.Write("请输入年龄:");
int age = int.Parse(Console.ReadLine());

// 处理部分
string greeting = $"你好,{name}!";
string ageInfo = $"你今年{age}岁";

// 输出部分
Console.WriteLine(greeting);
Console.WriteLine(ageInfo);

添加注释说明

// 1. 初始化数据
double price = 99.99;
int quantity = 3;

// 2. 计算总价
double subtotal = price * quantity;
double tax = subtotal * 0.08; // 8%税率
double total = subtotal + tax;

// 3. 显示结果
Console.WriteLine($"小计:{subtotal:C}");
Console.WriteLine($"税金:{tax:C}");
Console.WriteLine($"总计:{total:C}");

程序结构只有三种

· 3 min read
Sébastien Lorber
Docusaurus maintainer
Yangshun Tay
Ex-Meta Staff Engineer, Co-founder GreatFrontEnd

程序结构只有三种:顺序、分支、循环。这句话正确吗?我认为 break 和 continue 也属于程序结构

这是一个非常经典且深刻的编程理论问题。

直接给结论:从结构化程序设计(Structured Programming)的理论定义来看,你的教材或老师是对的,但你的直觉也反映了现代编程的实际情况。

我们可以从以下两个维度来拆解这个问题:


1. 为什么说“只有三种”?(理论层面)

在计算机科学中,这被称为 Böhm-Jacopini 定理。该定理证明了:任何算法都可以只用这三种基本控制结构来表示。

结构核心逻辑形象比喻
顺序 (Sequence)代码按编写顺序从上到下执行。直行道,没有分叉。
分支 (Selection/Branch)根据条件的真假选择不同的路径(if, switch)。十字路口,根据红绿灯选路。
循环 (Iteration/Loop)重复执行一段代码直到满足退出条件(for, while)。操场跑圈,跑够数为止。

这三种结构之所以被视为“原子级”的基石,是因为它们足以构建任何复杂的逻辑。


2. 为什么 breakcontinue 不算独立结构?(语义层面)

你认为它们属于程序结构是有道理的,因为它们确实改变了程序的流向。但在计算机术语中,它们通常被归类为**“跳转语句”(Jump Statements)**,而不是“结构”。

  • 它们是“附属品”breakcontinue 不能独立存在。如果没有循环(或 switch),它们就失去了存在的意义。
  • 它们的作用是“干预”而非“构建”
    • break 是强制结束当前循环。
    • continue 是跳过本次迭代,直接进入下一次判定。
  • 本质是受限的 goto:在早期的编程中,人们使用 goto 随处跳转,导致代码像“意大利面”一样混乱。为了规范化,现代语言引入了 breakcontinue 作为有纪律的跳转,用来辅助优化循环结构。

3. 你的理解错了吗?

你并没有错,你只是在用“功能角度”看问题,而定理是在用“最小完备集”看问题。

  • 理论上:不需要 break,你也可以通过修改循环条件(比如 while 的布尔值)来实现同样的功能。
  • 实践上:为了让代码更好读、更简洁,我们离不开 breakcontinue

小贴士:在 C# 中,除了这三种基本结构和跳转语句,还有一种特殊的结构叫 异常处理 (Exception Handling),即 try-catch-finally。虽然它本质上也涉及分支和跳转,但在现代应用开发中,它常被视为第四种重要的流控制方式。


总结

“顺序、分支、循环”是构建大厦的砖块、钢筋和水泥;而 breakcontinue 更像是电梯或紧急出口——它们很有用,但你不能只用电梯盖出一栋房子。

既然聊到了跳转,你想看看在嵌套循环中,如何优雅地使用 break 才能避免逻辑混乱吗?