Golang编译器函数重载错误不一致问题探讨

Golang编译器函数重载错误不一致问题探讨 我正在学习Go语言,并想确认Go是否支持函数重载。Go不支持函数重载,这本身没有问题。但是,编译器对于函数重载产生的错误信息并不一致。

如果你重载了一个函数,编译器会正确地识别出之前的声明。然而,在函数调用处,它抱怨的是对第一个声明的调用,而不是最后一个。

人们通常会期望它抱怨的是重复声明以及对重复声明的调用。

Go Playground - Go编程语言

./prog.go:11:6: f redeclared in this block
prog.go:7:6: previous declaration
./prog.go:16:6: f redeclared in this block
prog.go:11:10: previous declaration
./prog.go:23:3: not enough arguments in call to f
have ()
want (int, int)
./prog.go:24:3: not enough arguments in call to f
have (number)
want (int, int)

Go构建失败。

这里是另一个例子,但涉及的是变量重复声明,而不是函数重复声明。

Go Playground - Go编程语言


更多关于Golang编译器函数重载错误不一致问题探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

感谢肖恩的解释。这可能不是一个错误。

通常,编译器在遇到任何符号错误时不会更新符号表。所以,我觉得这很奇怪。

语言规范在这方面说得不是很清楚。它基本上是说,不允许有多个声明,但它没有明确说明不允许重新声明

The Go Programming Language Specification - The Go Programming Language

Go 是一种开源编程语言,它使得构建简单、可靠、高效的软件变得容易。

更多关于Golang编译器函数重载错误不一致问题探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这很有趣,但我不认为这是一个错误。一旦你重新声明了函数,之后的所有内容都只是在这个初始问题上叠加。这就像一个语法错误:如果你在函数中漏掉了一个花括号,你会得到一个错误。然后,你可能会在文件的其他地方得到关于其他函数、常量、变量等不存在的错误,即使它们确实存在;这只是因为缺失的花括号破坏了命名空间。

由于 Go 语言不支持重载,它可能在某个地方有一些代码来报告名称被重新声明的情况,但仅此而已。也许它看起来像这样:

for _, obj := range compiledPkgObjects {
    if old, ok := pkgNamespace[obj.Name]; ok {
        log.Logf("redeclaration of %s ...", obj.Name)
    }
    pkgNamespace[obj.Name] = obj
}

所以,首先定义了 f(),然后 f(int) 覆盖了它,接着 f(int, int) 又覆盖了那个。当 main 中的名称被解析时,它查找 f 并看到的是 f(int, int)

在Go语言中,函数重载确实不被支持,编译器会按照语言规范处理重复声明。你观察到的错误信息不一致问题,实际上是编译器按照作用域和解析顺序进行报错的结果。

对于函数重复声明,编译器会按顺序检测到每个重复声明,并指向之前的声明位置。在调用时,编译器会使用当前作用域中最后解析到的函数签名进行类型检查。这就是为什么调用错误显示的是want (int, int),因为那是最后一个被解析的函数签名。

示例代码:

package main

func f(a, b int) {}  // 第一个声明
func f(s string) {}   // 重复声明,编译器报错指向第一个
func f(x int) {}      // 再次重复声明,编译器报错指向上一个

func main() {
    f()  // 错误:not enough arguments in call to f
         // want (int) - 使用最后一个解析到的签名进行检查
}

对于变量重复声明,行为类似:

package main

var x int
var x string  // 错误:x redeclared in this block

func main() {
    println(x)  // 这里x的类型是string,因为它是最后解析的声明
}

编译器在解析阶段会收集所有声明,当遇到重复声明时记录错误,但在后续的类型检查阶段,会使用最后解析到的声明进行验证。这种设计确保了即使在有编译错误的情况下,编译器仍能继续分析代码的其他部分。

回到顶部