-
前言
注:库源码文件:不具有声明自己属于main代码包、包含无参数声明和结果声明的main函数的源码文件
库源码文件不能直接被运行,它仅用于存放程序实体。这些程序实体可以被其他代码使用,两者可以带同一源码文件中也可以在其他源码文件,甚至其他代码包中,一般我们是先声明(或者说定义)程序实体,然后再去使用
注:程序实体:变量,常量,函数,结构体和接口的统称。
怎样把命令源码中的代码拆分到其他位置?
如果在同一个代码包中,可以直接拆分
// demo4.go
package main
import (
"flag"
)
var StudentName string
func init() {
flag.StringVar(&StudentName, "name", "Default name", "Some description.")
}
func main() {
flag.Parse()
hello(StudentName)
}
// demo4_lib.go
package main
import (
"fmt"
)
func hello(StudentName string) {
fmt.Printf("Hello, %s!\n", StudentName)
}
如果不在同一代码包中,需要把调用的函数名改成首字母大写的函数名,调用时加入包名
// demo5_lib.go
package lib5
import (
"fmt"
)
func Hello(StudentName string) {
fmt.Printf("Hello, %s!\n", StudentName)
}
代码包声明的基本规则:
1、 同目录下源码文件代码包声明(package)语句要一致,必须要同属于一个代码包。特殊情况是,如果该目录中有命令源码文件,那么其他源码文件也要声明属于main包(因为命令源码文件属于该包),否则在构建和运行的时候就会出错。
2、源码文件声明的代码包的名称可以与其所在目录的名称不同,但是在构建该代码包时,生成结果文件的主名称与其父目录(所在目录)的名称一致。
对于命令源码文件,构建生成的可执行文件的主名称会与其父目录名称相同。
代码包导入路径总会与其所在的目录相对路径一致吗
例如:库源码文件demo5_lib.go所在目录的相对路径是puzzlers/article3/q2/lib,而它却声明自己属于lib5(package lib5),在这种情况下,该包的导入路径到底是如何的?
先使用lib的相对路径,安装前面提供的代码包:
go install 36class/q5/lib
该命令执行成功后,会在当前过去(GoPath)的pkg目录下,生成相应的归档文件,如:
pkg/windows_amd64/36class/q5/lib.a
其中“windows_amd64”就表示平台相关目录,由Go编译时自动生成子目录,后面的目录与源码文件所在的目录相对应。
特别注意:源码文件所在的目录相对于GOPATH下src目录的相对路径,就是它代码包导入路径,而实际使用时给定的限定符(如上述文件中的“lib5.”)必须要与它声明所属的代码包名称一致。
所以,要么把 :
package lib5
改为:
package lib
然后使用lib.Hello,如果保持lib5不变,那么就在调用限定符时使用“lib5.Hello”。
由上可知,代码包导入路径可以和包名不一致,在使用的时候需要使用包名。
-
对于程序实体,还有其他的访问权限规则吗?
有。在Go1.5版本之后,通过创建“internal代码包”可以让一些程序实体仅仅能被当前模块中的其他代码引用,这叫“模块级私有”。
具体规则为:
internal代码包中声明的程序实体(即使是公开的)仅仅能被该代码包的直接父包(父目录)及其子包中的代码引用。
引用前需要先导入internal包。
对于其他代码包,即使导入该internal包,也无法通过编译。
-
问题:(待考究)
1、如果你需要导入两个代码包,而这两个代码包的导入路径的最后一级是相同的,比如:dep/lib/flag和flag,那么会产生冲突吗?
答:import后路径最后一级相同,不一定会冲突。
分为两种情况:
a.如果文件夹下文件声明的包名相同,则肯定冲突,会报错redeclared。
b.如果文件夹下文件声明的包名不同,也不会冲突。
2、如果产生冲突,那么该如何解决,有几种方式?
答:a.给包设置别名,调用的时候来区分开不同的package,比如:import(b "bbbb")
b.导入的点操作,import(. "bbbb")。这样就可以直接调用bbbb下面的函数而不用再bbbb.funcname的方式调用。
c.如果只是想引入某包并没有在代码中实际调用则可以这么处理来避免冲突:import(_ "bbbb")
d.像第一问一样采取不同的包名声明,毕竟包名不一定要和文件夹名一样
不过总的推荐还是方法a。