为什么 Golang 允许在全局范围内循环引用,但不允许在函数范围内循环引用

Min*_*ing 1 go circular-reference

当我使用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")
}
Run Code Online (Sandbox Code Playgroud)

然而,将定义移到函数之外就可以了

package main

import "fmt"

type Student struct {
    Courses []*Course
}
type Course struct {
    Students []*Student
}

func main() {
    fmt.Printf("This works")
}

Run Code Online (Sandbox Code Playgroud)

可以自己尝试一下https://go.dev/play/p/GI53hhlUTbk

为什么会这样呢?我怎样才能让它在函数范围内工作?

C++中是否有类似typedef的语法,所以我们可以先声明一个结构体,然后再定义它?

谢谢!

Cer*_*món 6

循环类型引用可以在包块中进行但不能在函数内部进行。规范中关于声明和范围的部分说:

\n
\n
    \n
  1. 表示在顶层(任何函数外部)声明的常量、类型、变量或函数(但不是方法)的标识符的范围是包块。
  2. \n
\n

\xe2\x8b\xae

\n
    \n
  1. 函数内部声明的类型标识符的范围从 TypeSpec 中的标识符开始,到最内层包含块的末尾结束。
  2. \n
\n
\n

循环引用在包级别工作,因为在包级别声明的类型的作用域为整个包块。

\n

函数中声明的类型的范围从声明开始,而不是从包含块的开头开始。类型不能引用稍后在函数中声明的类型,因为这些类型不在作用域内。\n因此,不允许对函数中声明的类型进行循环类型引用。

\n

没有一种方法可以先声明类型的名称,然后再定义该类型。

\n