Go 中的包以及函数/变量的可见范围
看了上一篇函数的内容,可以发现漏掉了一个点,就是 函数可见范围。
在 Java 中,我们可以通过 private
protected
public
快速的区分,但是到了 Go 没有这些关键字了。我一脸懵逼,要如何区分呢?
如何创建包
首先我们要知道 可见范围 的重点在于 范围,那Go中如何去界定这个范围的边界呢?这个就在 包 的定义。
和 Java 语言中类的定义不同,在 Go 中,多个文件只要在一个包下,其实可以看作是 Java 中一个类。这里我们同样列出代码。
我们新建 2 个目录, 3 个文件如下:
// visible1.go
package visible
var a int = 1
var A int = 100
func getSmallA() int {
return a
}
func GetBigA() int {
return A
}
// visible2.go
package visible
var A int = 123 // 报错,因为已经被定义了
func GetBigA() int { // 报错
return A
}
func geta() int {
a := 123; // 不报错
return a
}
如上代码所示,加上我们之前知道的规范:Go语言里,同一个目录下的包名需要一致 可知,我们新建一个目录,取了一个包名,那就已经完成了一个包的创建。
接下来我们会对 同一个 package 内 、不同 package 内 的访问展开叙述。
同一个 package(包内)
当我们在 visible2.go
文件中定义同名的变量或者方法时,编译器会提示报错:
GetBigA redeclared in this block compiler [DuplicateDecl] visible1.go(10, 6): other declaration of GetBigA
我们定义的 A
也会报相同的错误,但是在 geta
函数中的 a
却不会。这是因为他们的作用域不同,一个是 全局变量,一个是 局部变量。
局部变量仅生效于自身所在的块内,而全局变量则可以作用于整个 package
甚至 package
外部。
因此我们知道同一个 package 下,它们是共享变量定义的,不允许同一 package
下 、同一作用范围内出现重复定义的变量和方法。所以也是我上边说的同一个 package 下的多个文件,类似于 Java 的一个类。(不足之处欢迎指正哈)
我们可以通过 go build
命令来检查代码是否能正常编译, 该命令不会直接生成可执行的代码。
不同 package (包外)
那在 package
外,Go 是怎么控制访问范围的呢?我们如果想要访问上边的 A 要如何访问呢?
首先说 Go 是如何控制访问范围的。
Go 没有提供 public
或 private
关键字,用于标明是否可以从包的内外部调用变量或函数。 但 Go 须遵循以下两个简单规则:
- 如需将某些内容设为 专用内容,请以 小写字母 开始。≈
private
- 如需将某些内容设为 公共内容,请以 大写字母 开始。≈
public
反过来,我们再看 visible1.go 中的代码可以发现,其中的 a
变量就是不能出包的,而 A
变量则可以在包外被访问。
当然,我们想要访问 visible 目录下的变量或者方法并没有这么简单,在此之前,我们要创建模块
Go 模块通常包含可提供相关功能的包。 包的模块还指定了 Go 运行你组合在一起的代码所需的上下文,例如编写代码时所用的 Go 版本。
例如我们要为 visible
包创建对应的模块,我们需要先到它的目录 visible\
下,然后执行 go mod init 模块名称
命令创建对应模块的包
go mod init beatree/visible/visible
执行完成后会在目录下新增 go.mod 文件
文件内容如下:
module beatree/visible/visible
go 1.20
我们现在来看 visibleMain.go
的代码
package main
import (
"beatree/visible/visible" // 引入 visible 模块
"fmt"
)
func main() {
// fmt.Println(visible.a); // a not exported by package visible
// fmt.Println(visible.getSmallA()); // getSmallA not exported by package
fmt.Println(visible.A);
fmt.Println(visible.GetBigA());
}
在 Go 中,包名称需遵循约定。 包使用其导入路径的最后一部分作为名称。在代码中我们可以看到,小写字母开头的变量和方法都无法被访问到。而大写的则可以。
就在运行时,大树踩了另一个坑:
visibleMain.go:4:2: package beatree/visible/visible is not in GOROOT (D:\CodeTime\******\visible\visible)`
这是怎么回事儿呢?下篇文章再说吧~