11

Google 的新语言Go试图通过明确要求实际使用模块中列出的所有依赖项来简化依赖项管理。编译器将拒绝声明对模块的依赖项而不使用该模块中的任何内容的模块。

包自行导入或在不引用任何导出标识符的情况下导入包是非法的。

我可以想到一些明显的优势(例如更清洁的模块),但也许有一些不明显的优势。我能想到的唯一缺点是编译器过于迂腐,在重构过程中抱怨太多,但也许还有更多?

您是否有使用其他语言执行此操作的经验?这种方法的优点和缺点是什么?

4

3 回答 3

5

不仅需要显式使用所有依赖项,还必须使用所有变量。当您有未使用的变量时,编译器会给您错误。

他们很烦人。但这会让其他人高兴,因为他们得到了干净的代码。

我在想可能 Go 设计者打算将 Go 成为一种很大程度上依赖于 IDE 的语言。

于 2009-12-01T11:43:19.537 回答
1

我猜最大的动机和最大的结果是编译时间的改进。技术预览视频强调了他们在短时间内编译大量代码的能力(他们的例子是 MacBook 上 8 秒内 200,000 行代码 - 没有给出机器规格)。

同样在技术视频中,他们特别提到他们实现的最大方法之一是改变模块的编译和链接方式。

这是一个在当前 C/C++ 系统中如何工作的示例:

A 类在头文件 C_H 中定义并在 C_CPP 中实现。B 类从 C 派生并在文件 B_H 和 B_CPP 中实现。A 类从 B 派生并在文件 A_H 和 A_CPP 中实现。

由于派生链,A_CPP 包括 A_H、B_H 和 C_H。B_CPP 包括 B_H 和 C_H。C_CPP 包括 C_H。由于 C 预处理器本质上将 #include 转换为剪切和粘贴操作的性质,C_H 的内容通过编译器运行 3 次,而 B_H 则运行两次。

此外,A_CPP、B_CPP 和 C_CPP 的内容都存在于它们自己的目标文件中。因此,当链接器解析 Ao 时,它被迫同时加载和处理 Bo 和 Co。此外,当它解析 Bo 时,它必须再次处理 Co。

预编译的头文件可以帮助解决这个问题的第一部分,但它们也可能很难维护,我知道很多开发人员出于这个原因根本不使用它们。它也没有从根本上改变问题 - 标头仍然在多个级别上多次处理,只是现在处理的是预编译的二进制文件而不是源代码。几个步骤被删掉了,但不是整个过程。

Go 以不同的方式处理事情。用他们技术谈话中直接从PDF 中摘录的话说

“Go 编译器从目标文件中提取传递依赖类型信息——但只提取它需要的信息。如果 A.go 依赖于 B.go 依赖于 C.go: - 编译 C.go,B.go,然后 A.go。 - 编译 A.go,编译器读取 Bo 而不是 Co 在规模上,这可能是一个巨大的加速。”

好的,轻微的切线就完成了。为什么这是相关的?答案也在 Go Tech Talk PDF 中:

“包模型:显式依赖关系以实现更快的构建。”

我猜 Go 开发人员的立场是,当编译时间以秒为单位时,即使对于非常大的项目,开发人员保持更高效编译时间那么短。假设我需要 8 秒来编译 200,000 行代码并发现我有一个无关的包导入,5-10 秒(使用良好的 IDE,或者对您的开发环境非常熟悉)找到并修复它,并且再过 8 秒重新编译。将其称为总共 30 秒 - 现在我所有未来的编译都保持在 10 秒的范围内。或者我们可以通过包含不必要的依赖项让我们的模块增长,并观察编译时间从 8 秒增加到 10、12 或 15 秒。这看起来并不多,因为我们都习惯于以分钟为单位来编译时间 - 但是当您开始意识到这是 25% 的性能下降时,您会停下来思考一分钟。

Go 编译时间已经快如闪电了。还要考虑处理器速度仍在增加(如果没有过去那么多的话),并且可用内核的数量也在增加(并且编译大量代码非常适合多线程)。今天 8 秒内 200,000 行代码意味着可以想象 200,000 行代码在 10 年内基本上是瞬间编译的。我认为 Go 团队在这里做出了一个有意识的决定,让编译时间成为过去,虽然你提出的问题只是其中的一小部分,但它仍然是其中的一部分。

另一方面,Go 团队似乎也发展了一种语言设计哲学,强制一些良好的编程实践。值得称赞的是,他们已经努力实现这一目标而没有严重的绩效处罚,并且基本上取得了成功。[旁白:我能想到的实际上影响性能的唯一两件事是垃圾收集和强制初始化变量——后者在当今时代相当微不足道。] 这会激怒一些程序员,同时让其他人高兴. 这是编程世界中一个古老而古老的论点,而且很清楚 Go 的哪一方失败了,不管你喜不喜欢。

我认为这两种力量共同影响了他们的决定,我认为最终这是一个好方法,尽管我支持这里的其他评论者,他们建议允许使用“--strict”标志或类似的标志来实现这一点特定行为可选,尤其是在项目生命周期的早期阶段。当我第一次开始编写我知道以后需要的代码时,我可以很容易地看到自己定义变量或包含包,即使我还没有编写需要它们的代码。

于 2009-12-01T15:33:08.213 回答
0

正如 yuku 所提到的,如果您有一个与 Netbeans 和 Eclipse 可以为 java 做的事情相当的 IDE,那么您实际上不必关心这类事情。

右键单击空白处的小灯泡,然后选择“删除所有未使用的依赖项”。

对于未使用的变量,它们通常会带有波浪形的下划线,并且很容易发现。

这里唯一的区别是,与其他语言不同,除了 IDE 之外,您实际上还有编译器抱怨,但如果您仍然使用 IDE,这不会成为问题。

在工作中,我们的编码政策几乎规定我们必须(我们自己)做同样的事情,当然还有其他语言。所以我会说这种方法确实有真正的应用。尽管恕我直言,编译器应该为开发人员提供打开和关闭此行为的选项。严格模式有人吗?

于 2009-12-01T12:16:16.880 回答