Why Golang allows circular reference in global scope but not in function scope

huangapple go评论87阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2022年8月30日 07:10:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/73535543.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定