Go语言入门基础之库源码文件

本文介绍了Go语言中库源码文件的概念和作用,包括如何拆分命令源码文件,代码包的导入路径规则,以及程序实体的访问权限。强调了源码文件的包名应与其目录名一致,首字母大写的程序实体才能被外部引用,并提到了内部包(internal)的访问权限控制。文章适合Go语言初学者,帮助理解Go代码的组织和包管理。

本场 Chat 旨在一分钟教你学会源码文件的拆分以及库源码文件的作用。

在本场 Chat 中,会讲到如下内容:

- 什么是使用库源码文件

- 拆分命令源码文件

- 代码包的导入路径总会与其所在目录的相对路径

- 什么样的程序实体才可以被当前包外的代码引用

概念:何为库源码文件

不具备命令源码文件的声明自己属于main包、包含无参数声明、结果声明的main参数的特征的源码文件,即为库源码文件。

注意:库源码文件不能被直接运行,它仅用于存放程序实体。只要遵从 Go 语言规范,这些程序实体就可以被其他代码使用。这些“其他代码”可以与被使用的程序实体在同一个源码文件内,也可以在其他源码文件,甚至其他代码包中。

程序实体是什么?

在 Go 语言中,它是变量、常量、函数、结构体和接口的统称。我们总是会先声明(或者说定义)程序实体,然后再去使用。比如之前的例子中,我们先定义了变量testStr,然后在main函数中调用fmt.Printf函数的时候用到了它。

程序实体的名字被统称为标识符。标识符可以是任何 Unicode 编码可以表示的字母字符、数字以及下划线“_”,但是其首字母不能是数字。和java一样。

问题:怎样把命令源码文件中的代码拆分到其他源码文件?

我们可以把上一节中的文件分成如下:

#demo.go

package main


import (
  "flag"
)


var testStr string


func init(){
  flag.StringVar(&testStr, "testStr", "小码哥Damon", "介绍说明")
}


func main()  {
  //用于真正解析参数
  flag.Parse()
  //fmt.Printf("Hello, %s!\n", testStr)
  test(testStr)
}

#demo_lib.go

【1】


import "fmt"


func hello(name string) {
  fmt.Printf("Hello, %s!\n", name)
}

那么【1】该怎么写呢?

显然:写入

package main

然后执行:

go run demo.go demo_lib.go
Hello, 小码哥Damon!

这里,我把上面两个文件放在一个目录下。

注意,demo.go 和 demo_lib.go 都声明自己属于main包。这种用法,即:源码文件声明的包名可以与其所在目录的名称不同,只要这些文件声明的包名一致就可以。

之前说过,需要把项目代码的根目录加入到环境变量GOPATH中,这样使其目录成为工作区之一。

问题解析

这个问题考察的是代码包声明的基本规则。这里总结一下:

第一条规则,同目录下的源码文件的代码包声明语句要一致。也就是说,它们要同属于一个代码包。这对于所有源码文件都是适用的。

如果目录中有命令源码文件,那么其他种类的源码文件也应该声明属于main包。这也是我们能够成功构建和运行它们的前提。

第二条规则,源码文件声明的代码包的名称可以与其所在的目录名不同。在针对代码包进行构建时,生成的结果文件的主名称与其父目录名一致。

对于命令源码文件而言,构建生成的可执行文件的主名称会与其父目录名相同。

问题:怎样把命令源码文件中的代码拆分到其他代码包?

我们把代码demo.go文件放在了一个叫src目录下的demo2目录下,然后在demo2目录下创建一个lib目录,再把demo_lib.go放到该目录下。

#src/demo2

package main


import (
  "flag"
  "demo2/lib"
)


var name string


func init() {
  flag.StringVar(&name, "name", "everyone", "The greeting object.")
}


func main() {
  flag.Parse()
  lib.Hello(name)
}

#src/demo2/lib

package lib3


import "fmt"


func Hello(name string) {
  fmt.Printf("Hello, %s!\n", name)
}

这里可以看到改变的是:第一个改动是,我把代码包声明语句由package main改为了package lib3。第二个改动是,我把全小写的函数名hello改为首字母大写的Hello。

基于这点,我们再看问题:代码包的导入路径总会与其所在目录的相对路径一致吗?

库源码文件 demo_lib.go 所在目录的相对路径是demo2/lib,而它却声明自己属于lib3包。在这种情况下,该包的导入路径是demo2/lib,还是demo2/lib3?

如果是这样会报错:为什么会是这样?

根本原因就是,我们在源码文件中声明所属的代码包与其所在目录名不同。请记住,源码文件所在的目录相对于 src 目录的相对路径就是它的代码包导入路径,而实际使用其程序实体时给定的限定符要与它声明所属的代码包名称对应。

有两个方式可以使上述构建成功完成。我在这里选择把 demo_lib.go 文件中的代码包声明语句改为package lib。理由是,为了不让该代码包的使用者产生困惑,我们总是应该让声明的包名与其父目录的名称一致。

问题:怎样的程序实体才可以被当前包外的代码引用?

为什么要把 demo_lib.go 文件中的那个函数名称hello的首字母大写?实际上这涉及了 Go 语言中对于程序实体访问权限的规则。超级简单,名称的首字母为大写的程序实体才可以被当前包外的代码引用,否则它就只能被当前包内的其他代码引用。通过名称,Go 语言自然地把程序实体的访问权限划分为了包级私有的和公开的。对于包级私有的程序实体,即使你导入了它所在的代码包也无法引用到它。

问题:还有其他的权限规则来访问程序实体吗?

答案是肯定的。在 Go 1.5 及后续版本中,我们可以通过创建internal代码包让一些程序实体,仅仅能被当前模块中的其他代码引用。这被称为 Go 程序实体的第三种访问权限:模块级私有。

详细规则:internal代码包中声明的公开程序实体仅能被该代码包的直接父包及其子包中的代码引用。当然,引用前需要先导入这个internal包。对于其他代码包,导入该internal包都是非法的,无法通过编译。

个人网站:http://www.damon8.cn

 

热文推荐

Go语言入门基础之命令源码文件

Springcloud Oauth2 HA篇

Spring Cloud Kubernetes之实战一配置管理

Spring Cloud Kubernetes之实战二服务注册与发现

Spring Cloud Kubernetes之实战三网关Gateway

Ubuntu下K8S部署指南,单机、集群,带你入坑

如有收获,点个在看,谢谢

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值