源码文件分为三种,即:命令源码文件、库源码文件和测试源码文件。
命令源码文件
- 独立程序入口
- 属于main包,包含无参数无结果的main函数
- 通过go run命令运行,可接受命令行参数
- main函数执行的结束以为当前程序运行结束
- 同一个代码包中不要放多个命令源码文件
- 命令源码文件与库源码文件不要放在同一个代码包
- 构建后生成可执行文件,位于命令执行目录
- 安装后生成可执行文件,位于当前工作区的bin子目录或gobin包含的目录
库源码文件
- 专门用于放置可供其他代码使用的程序实体
- 构建后只生产临时文件,位于操作系统临时目录下,作用在于检查和验证
- 安装后生成归档文件,位于当前工作区的pkg子目录,即静态链接库文件
测试源码文件
- 功能测试源码文件
- 性能基准测试源码文件
- 示例测试源码文件
一、命令源码文件
1.1命令源码文件介绍
命令源码文件是程序的运行入口,如果一个源码下载文件声明属于main包,并且包含一个无参数声明且无结果声明的main函数,那么它就是命令源码文件。
package main
import (
//flag包用于接收和解析命令参数
"flag"
//fmt包含有格式化I/O函数
"fmt"
)
var name string
func init() {
flag.StringVar(&name, "name", "everyone", "The greeting object.")
//第 1 个参数是用于存储该命令参数值的地址
//第 2 个参数是为了指定该命令参数的名称
//第 3 个参数是为了指定在未追加该命令参数时的默认值
//第 4 个函数参数,即是该命令参数的简短说明
}
func main() {
//函数flag.Parse用于真正解析命令参数,并把它们的值赋给相应的变量;对该函数的调用必须在所有命令参数存储载体的声明和设置之后,并且在读取任何命令参数值之前进行。
flag.Parse()
fmt.Printf("Hello, %s!\n", name)
}
[root@zijie workspace]# go run demo1.go -name="Zijie"
Hello, Zijie!
[root@zijie workspace]# go run demo1.go --help
//go run命令构建上述命令源码文件时临时生成的可执行文件的完整路径。
Usage of /tmp/go-build990272550/b001/exe/demo1:
-name string
The greeting object. (default "everyone")
[root@zijie workspace]# go build demo1.go
[root@zijie workspace]# ./demo1 --help
Usage of ./demo1:
-name string
The greeting object. (default "everyone")
1.2 自定义命令源码文件的参数使用说明
对变量flag.Usage重新赋值。flag.Usage的类型是func(),即一种无参数声明且无结果声明的函数类型。
package main
import (
"flag"
"fmt"
"os"
)
var name string
// 方式3:创建一个私有的命令参数容器,不用全局的flag.CommandLine变量,把对flag.StringVar的调用替换为对cmdLine.StringVar调用,再把flag.Parse()替换为cmdLine.Parse(os.Args[1:])。其中的os.Args[1:]指的就是我们给定的那些命令参数。这样做就完全脱离了flag.CommandLine。
//var cmdLine = flag.NewFlagSet("question", flag.ExitOnError)
func init() {
// 方式2:在调用flag包中的一些函数(比如StringVar、Parse等等)的时候,实际上是在调用flag.CommandLine变量的对应方法。flag.CommandLine相当于默认情况下的命令参数容器。所以,通过对flag.CommandLine重新赋值,我们可以更深层次地定制当前命令源码文件的参数使用说明。flag.PanicOnError和flag.ExitOnError都是预定义在flag包中的常量。flag.ExitOnError的含义是,告诉命令参数容器,当命令后跟--help或者参数设置的不正确的时候,在打印命令参数使用说明后以状态码2结束当前程序。状态码2代表用户错误地使用了命令,而flag.PanicOnError与之的区别是在最后抛出“运行时恐慌(panic)”。
//flag.CommandLine = flag.NewFlagSet("", flag.PanicOnError)
flag.CommandLine = flag.NewFlagSet("", flag.ExitOnError)
flag.CommandLine.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage of %s:\n", "question")
flag.PrintDefaults()
}
// 方式3。
//cmdLine.StringVar(&name, "name", "everyone", "The greeting object.")
flag.StringVar(&name, "name", "everyone", "The greeting object.")
}
func main() {
// 方式1:对变量flag.Usage重新赋值。flag.Usage的类型是func(),即一种无参数声明且无结果声明的函数类型。对flag.Usage的赋值必须在调用flag.Parse函数之前。
//flag.Usage = func() {
// fmt.Fprintf(os.Stderr, "Usage of %s:\n", "question")
// flag.PrintDefaults()
//}
// 方式3。
//cmdLine.Parse(os.Args[1:])
flag.Parse()
fmt.Printf("Hello, %s!\n", name)
}
二、库源码文件
2.1 库源码文件介绍
库源码文件是不能被直接运行的源码文件,它仅用于存放程序实体,这些程序实体可以被其他代码使用(遵从 Go 语言规范)
在 Go 语言中,程序实体是变量、常量、函数、结构体和接口的统称。我们总是会先声明(或者说定义)程序实体,然后再去使用。程序实体的名字被统称为标识符。标识符可以是任何 Unicode 编码可以表示的字母字符、数字以及下划线“_”,但是其首字母不能是数字。
2.2 如何将命令源码文件拆分到其他库文件
命令源码文件
扫描二维码关注公众号,回复:
12681141 查看本文章
![](/qrcode.jpg)
package main
import (
//flag包用于接收和解析命令参数
"flag"
//fmt包含有格式化I/O函数
"fmt"
)
var name string
func init() {
flag.StringVar(&name, "name", "everyone", "The greeting object.")
//第 1 个参数是用于存储该命令参数值的地址
//第 2 个参数是为了指定该命令参数的名称
//第 3 个参数是为了指定在未追加该命令参数时的默认值
//第 4 个函数参数,即是该命令参数的简短说明
}
func main() {
//函数flag.Parse用于真正解析命令参数,并把它们的值赋给相应的变量;对该函数的调用必须在所有命令参数存储载体的声明和设置之后,并且在读取任何命令参数值之前进行。
flag.Parse()
fmt.Printf("Hello, %s!\n", name)
}
拆分主体
package main
import (
"flag"
)
var name string
func init() {
flag.StringVar(&name, "name", "everyone", "The greeting object.")
}
func main() {
flag.Parse()
hello(name)
}
拆分hellow函数
package main
import "fmt"
func hello(name string) {
fmt.Printf("Hello, %s!\n", name)
}
[root@zijie bin]# ll /root/workspace/src/puzzlers/article3/q1/
总用量 8.0K
-rw-r--r-- 1 root root 182 3月 5 10:18 demo1.go
-rw-r--r-- 1 root root 91 3月 5 10:19 demo1_lib.go
[root@zijie bin]# go build puzzlers/article3/q1
[root@zijie bin]# ls
q1
[root@zijie bin]# ./q1
Hello, everyone!
[root@zijie bin]# ./q1 --name="zijie"
Hello, zijie!
三、总结
- 同目录下的源码文件的代码包声明语句要一致
- 源码文件声明的代码包的名称可以与其所在的目录的名称不同
- 源码文件所在的目录相对于 src 目录的相对路径就是它的代码包导入路径,而实际使用其程序实体时给定的限定符要与它声明所属的代码包名称对应
- 为了不让该代码包的使用者产生困惑,我们总是应该让声明的包名与其父目录的名称一致
- 名称的首字母为大写的程序实体才可以被当前包外的代码引用,否则它就只能被当前包内的其他代码引用。通过名称,Go 语言自然地把程序实体的访问权限划分为了包级私有的和公开的。
- 在 Go 1.5 及后续版本中,我们可以通过创建internal代码包让一些程序实体仅仅能被当前模块中的其他代码引用。这被称为 Go 程序实体的第三种访问权限:模块级私有。具体规则是,internal代码包中声明的公开程序实体仅能被该代码包的直接父包及其子包中的代码引用。当然,引用前需要先导入这个internal包。对于其他代码包,导入该internal包都是非法的,无法通过编译。
本文内容来自Go语言核心36讲