Loading...
墨滴

盘胧

2021/08/12  阅读:36  主题:全栈蓝

golang-库源码文件

库源码文件

库源码文件是不能被直接运行的源码文件,它仅用于存放程序实体,这些程序实体可以被其他代码使用(只要遵从 Go 语言规范的话)。

其他代码:可以与被使用的程序实体在同一个源码文件内,也可以在其他源码文件,甚至其他代码包中

那么什么是程序实体?

在 Go 语言中,程序实体是变量、常量、函数、结构体和接口的统称。我们总是会先声明(或者说定义)程序实体,然后再去使用。我们先定义了变量name,然后在main函数中调用fmt.Printf函数的时候用到了它。再多说一点,程序实体的名字被统称为标识符。标识符可以是任何 Unicode 编码可以表示的字母字符、数字以及下划线“_”,但是其首字母不能是数字。从规则上说,我们可以用中文作为变量的名字。但是,我觉得这种命名方式非常不好,自己也会在开发团队中明令禁止这种做法。作为一名合格的程序员,我们应该向着编写国际水准的程序无限逼近。

拆分命令源码

怎样把命令源码文件中的代码拆分到其他库源码文件? 某个目录下有一个命令源码文件 demo4.go,如下:

package main

import (
  "flag"
)

var name string

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

func main() {
  flag.Parse()
  hello(name)
}

调用了一个叫作hello的函数,该函数放在lib.go:

package main

import "fmt"

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

可以看到,同样声明了package main,main.go 中才没有报错且可以执行。 执行命令看看:

MacBook-Pro demo % go run src/main.go src/lib.go
Hello, everyone!

可以看到:执行命令:o run src/main.go src/lib.go,才能执行完整,不能单独只run main.go! 为什么?

  • 在同一个目录下的源码文件都需要被声明为属于同一个代码包
  • 如果该目录下有一个命令源码文件,那么为了让同在一个目录下的文件都通过编译,其他源码文件应该也声明属于main包。

或者,像下面这样先构建当前的代码包再运行:

$ go build puzzlers/article3/q1
$ ./q1            
Hello, everyone!

在这里,我把 main.go 和 lib.go 都放在了一个相对路径为puzzlers/article3/q1的目录中。

  • 源码文件声明的包名可以与其所在目录的名称不同,只要这些文件声明的包名一致就可以。

问题解析

  • 第一条规则,同目录下的源码文件的代码包声明语句要一致。也就是说,它们要同属于一个代码包。这对于所有源码文件都是适用的。
    • 如果目录中有命令源码文件,那么其他种类的源码文件也应该声明属于main包。这也是我们能够成功构建和运行它们的前提。
  • 第二条规则,源码文件声明的代码包的名称可以与其所在的目录的名称不同。在针对代码包进行构建时,生成的结果文件的主名称与其父目录的名称一致。
    • 对于命令源码文件而言,构建生成的可执行文件的主名称会与其父目录的名称相同

在编写真正的程序时,我们仅仅把代码拆分到几个源码文件中是不够的。我们往往会用模块化编程的方式,根据代码的功能和用途把它们放置到不同的代码包中。不过,这又会牵扯进一些 Go 语言的代码组织规则

怎样把命令源码文件中的代码拆分到其他代码包? 其实拆分很简单,类似模块化编程,只不过golang需要拆分出不同的package, 不需要与目录同名

  • 拆分到其他库的代码,函数要从小写开头改成大写开头, 表示可以被外部引用——没错,这是go的风格,独树一帜吧?

导包到底是导目录名?还是package name? 我们在源码文件中声明所属的代码包与其所在目录的名称不同。请记住,源码文件所在的目录相对于 src 目录的相对路径就是它的代码包导入路径,而实际使用其程序实体时给定的限定符要与它声明所属的代码包名称对应——也就是说,导的是目录名——package name主要是给整个属于package的代码使用方便的——个人理解

规范来了: 为了不让该代码包的使用者产生困惑,我们总是应该让声明的包名与其父目录的名称一致

什么样的程序实体才可以被当前包外的代码引用? 超级简单,名称的首字母为大写的程序实体才可以被当前包外的代码引用,否则它就只能被当前包内的其他代码引用。

通过名称,Go 语言自然地把程序实体的访问权限划分为了包级私有的和公开的。对于包级私有的程序实体,即使你导入了它所在的代码包也无法引用到它。

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

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

看下目录: internal声明

总结

讨论了把代码从命令源码文件中拆分出来的方法,这包括拆分到其他库源码文件,以及拆分到其他代码包。

基本编码规则

  • 代码包声明规则
  • 代码包导入规则
  • 程序实体的访问权限规则

如果你需要导入两个代码包,而这两个代码包的导入路径的最后一级是相同的,比如:dep/lib/flag和flag,那么会产生冲突吗?

!答案: 取别名!

盘胧

2021/08/12  阅读:36  主题:全栈蓝

作者介绍

盘胧