【问题标题】:Why does Go allow compilation of unused function parameters?为什么 Go 允许编译未使用的函数参数?
【发布时间】:2014-03-21 02:48:56
【问题描述】:

当来自 C 语言时,Go 的一个更值得注意的方面是,如果在其中声明了一个未使用的变量,编译器将不会构建您的程序。那么,如果函数中声明了一个未使用的参数,为什么还要构建这个程序呢?

func main() {
    print(computron(3, -3));
}


func computron(param_a int, param_b int) int {
    return 3 * param_a;
}

【问题讨论】:

标签: variables parameters compilation go


【解决方案1】:

官方没有给出原因,但是在golang-nuts上给出的原因是:

未使用的变量总是一个编程错误,但它很常见 编写一个不使用所有参数的函数。

可以不命名这些参数(使用 _),但那可能 与

之类的功能混淆

func foo(_ string, _ int) // 这应该做什么?

这些名称,即使它们未被使用,也提供了重要的文档。

安德鲁

https://groups.google.com/forum/#!topic/golang-nuts/q09H61oxwWw

有时具有未使用的参数对于满足接口很重要,一个示例可能是在加权图上运行的函数。如果你想在所有边上实现一个成本一致的图,考虑节点是没有用的:

func (graph *MyGraph) Distance(node1,node2 Node) int {
    return 1
}

正如该线程所指出的,有一个有效的参数来只允许名为_ 的参数如果它们未被使用(例如Distance(_,_ Node)),但由于Go 1 future-compatibility guarantee,此时为时已晚。正如所提到的,一个可能的反对意见是参数,即使未使用,也可以隐式提供文档。

简而言之:没有具体的、具体的答案,只是他们最终只是做出了一个武断的(但仍然有根据的)决定,即未使用的参数比未使用的局部变量和导入更重要和有用。如果曾经有一个强有力的设计理由,那么它不会记录在任何地方。

【讨论】:

  • 我同意。有时您需要使用未使用的参数来实现函数以满足接口。
  • 我明白了 - 一流的函数和作为类型的函数。酷!
  • 这似乎很容易被类似于_ = node1 _=node2的成语覆盖
  • @jrodman 建议的成语(_ = node1;_ = node2 等单独的行)对我来说似乎更好,因为一旦学会,它明确地消除了“这是故意未使用的”与“这是意外未使用的”的歧义”。后者可能发生在笨拙的维护过程中,最好有一个明确的编程习惯,让人们明确地确认“我确实故意故意让这个不被使用”,如果简单地防止意外的隐式情况就更好了。
【解决方案2】:

主要原因是能够实现接口,这些接口指示具有特定参数的特定方法,即使您没有在实现中使用所有这些方法。这在@Jsor 的回答中有详细说明。

另一个很好的理由是,未使用的(局部)变量通常是错误或使用语言特性的结果(例如,在块中使用短变量声明 :=,无意中隐藏了“外部”变量)而未使用的函数参数从不(或很少)是错误的结果。

另一个原因可能是提供向前兼容性。如果你发布了一个库,你就不能在不破坏向后兼容性的情况下更改或扩展参数列表(在 Go 中没有函数重载:如果你想要 2 个具有不同参数的变体,它们的名称也必须不同)。

您可以提供一个导出的函数或方法,并向其中添加额外的 - 尚未使用的 - 或可选参数(例如 hints),以便您可以在未来的版本/发行版中使用它们你的图书馆。

尽早这样做会给您带来好处,即使用您的库的其他人无需更改其代码中的任何内容。

我们来看一个例子:

你想创建一个格式化函数:

// FormatSize formats the specified size (bytes) to a string.
func FormatSize(size int) string {
    return fmt.Sprintf("%d bytes", size)
}

你也可以马上添加一个额外的参数:

// FormatSize formats the specified size (bytes) to a string.
// flags can be used to alter the output format. Not yet used.
func FormatSize(size int, flags int) string {
    return fmt.Sprintf("%d bytes", size)
}

稍后您可以改进您的库和您的 FormatSize() 函数以支持以下格式标志:

const (
    FlagAutoUnit      = 1 << iota // Automatically format as KB, MB, GB etc.
    FlagSI                        // Use SI conversion (1000 instead of 1024)
    FlagGroupDecimals             // Format number using decimal grouping
)

// FormatSize formats the specified size (bytes) to a string.
// flags can be used to alter the output format.
func FormatSize(size int, flags int) string {
    var s string

    // Check flags and format accordingly
    // ...

    return s
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-11
    • 2013-06-21
    • 2023-03-27
    • 1970-01-01
    • 2015-02-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多