英文:
Why Golang allows circular reference in global scope but not in function scope
问题
我正在使用gormigrate编写数据库迁移,需要在函数作用域中定义两个结构体之间的多对多关系。但是在golang 1.19或1.18中,以下代码无法编译:
package main
import "fmt"
func main() {
type Student struct {
Courses []*Course
// [Error] ./prog.go:7:14: undefined: Course
}
type Course struct {
Students []*Student
}
fmt.Printf("This won't compile")
}
然而,将定义移到函数外部就可以正常工作:
package main
import "fmt"
type Student struct {
Courses []*Course
}
type Course struct {
Students []*Student
}
func main() {
fmt.Printf("This works")
}
你可以在https://go.dev/play/p/GI53hhlUTbk上尝试一下。
为什么会出现这种情况?如何在函数作用域中使其正常工作?
在C++中是否有类似于typedef的语法,可以先声明结构体,然后再定义它?
谢谢!
英文:
As I'm writing DB migrations using gormigrate, I need to define a many-to-many relationship between two structs in a function scope. But in golang 1.19 or 1.18 the following won't compile
package main
import "fmt"
func main() {
type Student struct {
Courses []*Course
// [Error] ./prog.go:7:14: undefined: Course
}
type Course struct {
Students []*Student
}
fmt.Printf("This won't compile")
}
However moving the definitions outside of the function will just work
package main
import "fmt"
type Student struct {
Courses []*Course
}
type Course struct {
Students []*Student
}
func main() {
fmt.Printf("This works")
}
Can try this yourself at https://go.dev/play/p/GI53hhlUTbk
Why is this the case? And how can I make it work in a function scope?
Is there a similar syntax to typedef in C++, so we can declare a struct first and then define it later?
Thanks!
答案1
得分: 6
在包block中,可以使用循环类型引用,但在函数内部不行。规范中的声明和作用域部分说明了以下内容:
> 2. 在顶层(任何函数外部)声明的常量、类型、变量或函数(但不包括方法)的标识符的作用域是包块。
>
> ⋮
>
>8. 在函数内部声明的类型标识符的作用域从TypeSpec中的标识符开始,直到最内层包含块的结束。
循环引用在包级别上起作用,因为在包级别上声明的类型的作用域是整个包块。
在函数中声明的类型的作用域从声明处开始,而不是从包含块的开头开始。类型不能引用在函数中后面声明的类型,因为这些类型不在作用域内。
因此,在函数中声明的类型不允许循环类型引用。
没有一种方法可以先声明类型的名称,然后再定义该类型。
英文:
Circular type references are possible in the package block, but not inside a function. The section on Declarations and Scopes in the specification says:
> 2. The scope of an identifier denoting a constant, type, variable, or function (but not method) declared at top level (outside any function) is the package block.
>
> ⋮
>
>8. The scope of a type identifier declared inside a function begins at the identifier in the TypeSpec and ends at the end of the innermost containing block.
Circular references work at package-level because types declared at package-level are scoped to the entire package block.
The scope of a type declared in a function begins at the declaration, not at the beginning of the containing block. A type cannot reference types declared later in the function because those types are not in scope.
It follows that circular type references are not allowed for types declared in a function.
There is not a way to declare the name of a type and later define the type.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论