mirror of
https://github.com/unknwon/the-way-to-go_ZH_CN.git
synced 2025-08-12 05:11:49 +08:00
9.5
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -20,3 +20,4 @@ _cgo_export.*
|
|||||||
_testmain.go
|
_testmain.go
|
||||||
|
|
||||||
*.exe
|
*.exe
|
||||||
|
.DS_Store
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
## 翻译进度
|
## 翻译进度
|
||||||
|
|
||||||
9.4 [精密计算和 big 包](eBook/09.4.md)
|
9.5 [自定义包和可见性](eBook/09.5.md)
|
||||||
|
|
||||||
## 支持本书
|
## 支持本书
|
||||||
|
|
||||||
|
111
eBook/09.5.md
111
eBook/09.5.md
@@ -1,76 +1,83 @@
|
|||||||
# 9.5 自定义包和可见性
|
# 9.5 自定义包和可见性
|
||||||
|
|
||||||
203
|
包是 Go 语言中代码组成和代码编译的主要方式。很多关于它们的基本信息已经在4.2章节中给出,最引人注目的便是可见性。现在我们来看看具体如何来使用自己写的包。在下一节,我们将回顾一些标准库中的包,自定义的包和标准库以外的包。
|
||||||
包是Go语言中代码组成和代码编译的主要方式。很多关于它们的基本信息已经在4.2章节中给出,最引人注目的便是可见性。现在我们来看看具体如何来使用自己写的包。在下一节,我们将回顾一些标准库中的包,自定义的包和标准库以外的包。
|
|
||||||
|
|
||||||
当写自己包的时候,要使用短小的不含有_(下划线)的小写单词来为文件命名。这里有个简单例子来说明包是如何相互调用以及可见性是如何实现的。
|
当写自己包的时候,要使用短小的不含有_(下划线)的小写单词来为文件命名。这里有个简单例子来说明包是如何相互调用以及可见性是如何实现的。
|
||||||
|
|
||||||
当前目录下(examples/chapter9)有一个名为package_test.go的程序, 它使用了自定义包pack1中pack1.go的代码。这段程序(联通编译链接生成的pack1.a)存放在当前目录下一个名为pack1的文件夹下。所以链接器将包的对象和主程序对象链接在一起。
|
当前目录下(examples/chapter9)有一个名为 package_test.go 的程序, 它使用了自定义包 pack1中pack1.go 的代码。这段程序(联通编译链接生成的pack1.a)存放在当前目录下一个名为 pack1 的文件夹下。所以链接器将包的对象和主程序对象链接在一起。
|
||||||
|
|
||||||
示例 9.4 [pack1.go](examples/chapter_9/pack1.go)
|
示例 9.4 [pack1.go](examples/chapter_9/pack1.go):
|
||||||
|
|
||||||
package pack1
|
```go
|
||||||
var Pack1Int int = 42
|
package pack1
|
||||||
var PackFloat = 3.14
|
var Pack1Int int = 42
|
||||||
|
var PackFloat = 3.14
|
||||||
|
|
||||||
func ReturnStr() string {
|
func ReturnStr() string {
|
||||||
return "Hello main!"
|
return "Hello main!"
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
它包含了一个整型变量PackInt和一个返回字符串的函数ReturnStr。这段程序在运行时不做任何的事情,因为它不包含有一个main函数。
|
它包含了一个整型变量 PackInt 和一个返回字符串的函数 ReturnStr。这段程序在运行时不做任何的事情,因为它不包含有一个 main 函数。
|
||||||
|
|
||||||
在主程序pack_test.go中这个包通过声明的方式被导入
|
在主程序 pack_test.go 中这个包通过声明的方式被导入
|
||||||
|
|
||||||
import “./pack1/pack1”
|
```go
|
||||||
|
import “./pack1/pack1”
|
||||||
|
```
|
||||||
|
|
||||||
import 的一般格式如下:
|
import 的一般格式如下:
|
||||||
|
|
||||||
import “包的路径或url地址“ 像 import "github.com/org1/pack1”
|
import “包的路径或url地址“ 像 import "github.com/org1/pack1”
|
||||||
|
|
||||||
路径是指当前目录的相对路径。
|
路径是指当前目录的相对路径。
|
||||||
|
|
||||||
示例 9.5 [package_test.go](examples/chapter_9/package_test.go)
|
示例 9.5 [package_test.go](examples/chapter_9/package_test.go):
|
||||||
|
|
||||||
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"./pack1/pack1"
|
"./pack1/pack1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var test1 string
|
var test1 string
|
||||||
test1 = pack1.ReturnStr()
|
test1 = pack1.ReturnStr()
|
||||||
|
fmt.Printf("ReturnStr from package1: %s\n", test1)
|
||||||
fmt.Printf(“Integer from package1: %d\n”, pack1.Pack1Int)
|
fmt.Printf(“Integer from package1: %d\n”, pack1.Pack1Int)
|
||||||
// fmt.Printf(“Float from package1: %f\n”, pack1.pack1Float)
|
// fmt.Printf(“Float from package1: %f\n”, pack1.pack1Float)
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
输出结果:
|
输出结果:
|
||||||
|
|
||||||
ReturnStr from package1: Hello main!
|
ReturnStr from package1: Hello main!
|
||||||
Integer from package1: 42
|
Integer from package1: 42
|
||||||
|
|
||||||
如果包 pack1 和我们的程序在统同一路径下,我们可以通过 `"import ./pack1"` 这样的方式来引入,但这不被视为一个好的方法。
|
如果包 pack1 和我们的程序在统同一路径下,我们可以通过 `"import ./pack1"` 这样的方式来引入,但这不被视为一个好的方法。
|
||||||
|
|
||||||
`fmt.Printf(“Float from package1: %f\n”, pack1.pack1Float)` 这行代码试图访问一个未引用的变量或者函数,甚至没有编译。将会返回一个错误:
|
`fmt.Printf(“Float from package1: %f\n”, pack1.pack1Float)` 这行代码试图访问一个未引用的变量或者函数,甚至没有编译。将会返回一个错误:
|
||||||
fmt.Printf(“Float from package1: %f\n”, pack1.pack1Float)这行代码试图访问一个未引用的变量或者函数,甚至没有编译。将会返回一个错误:
|
|
||||||
cannot refer to unexported name pack1.pack1Float
|
cannot refer to unexported name pack1.pack1Float
|
||||||
cannot refer to unexported name pack1.pack1Float
|
|
||||||
主程序利用的包必须在主程序编写之前被编译。主程序中每个 pack1 项目都要通过包名来使用使用:pack1.Item。具体使用方法请参见示例 4.6 和 4.7。
|
主程序利用的包必须在主程序编写之前被编译。主程序中每个 pack1 项目都要通过包名来使用使用:pack1.Item。具体使用方法请参见示例 4.6 和 4.7。
|
||||||
|
|
||||||
因此,按照惯例子目录和包之间有着密切的联系:为了区分不同包存放在不同的目录,每个包(所有属于这个包中的 go 文件)都存放在和包名相同的子目录下:
|
因此,按照惯例子目录和包之间有着密切的联系:为了区分不同包存放在不同的目录,每个包(所有属于这个包中的 go 文件)都存放在和包名相同的子目录下:
|
||||||
|
|
||||||
Import with . : import . “./pack1”
|
Import with . : import . “./pack1”
|
||||||
|
|
||||||
|
|
||||||
当使用.来做为包的别名时,你可以不通过包名来使用其中的项目。例如:`test := ReturnStr()`。
|
当使用.来做为包的别名时,你可以不通过包名来使用其中的项目。例如:`test := ReturnStr()`。
|
||||||
|
|
||||||
在当前的命名空间导入 pack1 包,一般是为了具有更好的测试效果。
|
在当前的命名空间导入 pack1 包,一般是为了具有更好的测试效果。
|
||||||
|
|
||||||
|
Import with _ : import _ “./pack1/pack1”
|
||||||
|
|
||||||
pack1包只导入其副作用,只执行了它的init函数并初始化了其中的全局变量
|
pack1包只导入其副作用,只执行了它的init函数并初始化了其中的全局变量
|
||||||
|
|
||||||
导入外部安装包:
|
导入外部安装包:
|
||||||
|
|
||||||
如果你要在你的应用中使用一个或多个外部包,首先你必须使用 go install(参见第 9.7 节)在你的本地机器上安装它们。
|
如果你要在你的应用中使用一个或多个外部包,首先你必须使用 go install(参见第 9.7 节)在你的本地机器上安装它们。
|
||||||
|
|
||||||
假设你想使用 http://codesite.ext/author/goExample/goex 这种托管在 googlecode, github,launchpad 等代码网站上的包。
|
假设你想使用 http://codesite.ext/author/goExample/goex 这种托管在 googlecode, github,launchpad 等代码网站上的包。
|
||||||
@@ -78,37 +85,38 @@ pack1包只导入其副作用,只执行了它的init函数并初始化了其
|
|||||||
你可以通过如下命令安装:
|
你可以通过如下命令安装:
|
||||||
|
|
||||||
go install codesite.ext/author/goExample/goex
|
go install codesite.ext/author/goExample/goex
|
||||||
go install codesite.ext/author/goExample/goex
|
|
||||||
将一个名为 codesite.ext/author/goExample/goex 的 map 安装在 `$GOROOT/src/` 目录下。
|
将一个名为 codesite.ext/author/goExample/goex 的 map 安装在 `$GOROOT/src/` 目录下。
|
||||||
|
|
||||||
|
|
||||||
通过以下方式,一次性安装,并导入到你的代码中:
|
通过以下方式,一次性安装,并导入到你的代码中:
|
||||||
|
|
||||||
import goex “codesite.ext/author/goExample/goex”
|
import goex “codesite.ext/author/goExample/goex”
|
||||||
|
|
||||||
|
因此你项目的路径将成为导入包的网络地址
|
||||||
|
|
||||||
在 http://golang.org/cmd/goinstall/ 的 go install 文档中列出了一些广泛被使用的托管在网络代码仓库的包的导入路径
|
在 http://golang.org/cmd/goinstall/ 的 go install 文档中列出了一些广泛被使用的托管在网络代码仓库的包的导入路径
|
||||||
|
|
||||||
包的初始化:
|
包的初始化:
|
||||||
|
|
||||||
程序的执行开始于导入包,初始化 main 包然后调用 main 函数。
|
程序的执行开始于导入包,初始化 main 包然后调用 main 函数。
|
||||||
程序的执行开始于导入包,初始化main包然后调用main函数。
|
|
||||||
一个没有导入的包将通过分配初始值给所有的包级变量和调用源码中定义的包级 init 函数来初始化。一个包可能有多个 init 函数甚至在一个源码文件中。它们的执行是无序的。这是最好的例子来测定包的值是否只依赖于相同包下的其他值或者函数。
|
一个没有导入的包将通过分配初始值给所有的包级变量和调用源码中定义的包级 init 函数来初始化。一个包可能有多个 init 函数甚至在一个源码文件中。它们的执行是无序的。这是最好的例子来测定包的值是否只依赖于相同包下的其他值或者函数。
|
||||||
|
|
||||||
|
init 函数是不能被调用的。
|
||||||
|
|
||||||
导入的包在包自身初始化前被初始化,而一个包在程序执行中只能初始化一次。
|
导入的包在包自身初始化前被初始化,而一个包在程序执行中只能初始化一次。
|
||||||
|
|
||||||
|
编译并安装一个包(参见第 9.7 节):
|
||||||
|
|
||||||
|
在 Linux/OSX 下可以用类似第 4.3 节的 Makefile 脚本做到这一点:
|
||||||
|
|
||||||
|
include $(GOROOT)/src/Make.inc
|
||||||
TARG=pack1
|
TARG=pack1
|
||||||
TARG=pack1
|
GOFILES=\
|
||||||
GOFILES=\
|
pack1.go\
|
||||||
pack1b.go\
|
pack1b.go\
|
||||||
include $(GOROOT)/src/Make.pkg
|
include $(GOROOT)/src/Make.pkg
|
||||||
include $(GOROOT)/src/Make.pkg
|
|
||||||
确保的它可执行性通过 `chmod 777 ./Makefile`。
|
确保的它可执行性通过 `chmod 777 ./Makefile`。
|
||||||
|
|
||||||
内置声明了自动检测机器体系结构和使用正确的编译器和链接器的功能。
|
内置声明了自动检测机器体系结构和使用正确的编译器和链接器的功能。
|
||||||
@@ -119,19 +127,24 @@ go install(参见9.7章节,从Go1的首选方式)同样复制pack1.a到本地
|
|||||||
|
|
||||||
如果不可取或不被允许,通过 6/8g 使用 -I 选项来编译:
|
如果不可取或不被允许,通过 6/8g 使用 -I 选项来编译:
|
||||||
|
|
||||||
如果不可取或不被允许,通过6/8g使用-I选项来编译:
|
6g—I map_pack1 package_test.go # where map_pack1 is the map which contains pack1.a
|
||||||
|
|
||||||
6g—I map_pack1 package_test.go # where map_pack1 is the map which contains pack1.a
|
(I 选项让编译器查找选项后的目录下是否包含这个包)
|
||||||
|
|
||||||
|
使用 6/8l 的 -L 选项链接:
|
||||||
使用6/8l的-L选项链接:
|
|
||||||
|
|
||||||
6l—L map_pack1 package_test.6
|
6l—L map_pack1 package_test.6
|
||||||
|
|
||||||
当第13章我们遇到使用测试工具进行测试的时候我们将重新回到自己的包的制作和编译这个话题。
|
当第 13 章我们遇到使用测试工具进行测试的时候我们将重新回到自己的包的制作和编译这个话题。
|
||||||
|
|
||||||
练习:
|
练习:
|
||||||
|
|
||||||
问题9.1:
|
问题9.1:
|
||||||
|
|
||||||
(a)一个包能分成多个源文件么?
|
(a)一个包能分成多个源文件么?
|
||||||
|
|
||||||
|
(b)一个源文件是否能包含多个包?
|
||||||
|
|
||||||
|
练习 9.3:
|
||||||
|
创建一个程序 main_greetings.go 能够和用户说 "Good Day" 或者 "Good Night"。不同的问候应该放到 greetings 包中。
|
||||||
|
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
# 9.6 为你的自定义包使用godoc
|
# 9.6 为自定义包使用 godoc
|
||||||
|
|
||||||
|
208
|
||||||
godoc工具(3.6章节)在显示自定义包中的注释也有很好的效果:注释必须以//开始并无空行放在声明(包,类型,函数)前。godoc会为每个文件生成一系列的网页。
|
godoc工具(3.6章节)在显示自定义包中的注释也有很好的效果:注释必须以//开始并无空行放在声明(包,类型,函数)前。godoc会为每个文件生成一系列的网页。
|
||||||
|
|
||||||
例如:
|
例如:
|
||||||
|
@@ -78,6 +78,7 @@
|
|||||||
- 9.3 [锁和 sync 包](09.3.md)
|
- 9.3 [锁和 sync 包](09.3.md)
|
||||||
- 9.4 [精密计算和 big 包](09.4.md)
|
- 9.4 [精密计算和 big 包](09.4.md)
|
||||||
- 9.5 [自定义包和可见性](09.5.md)
|
- 9.5 [自定义包和可见性](09.5.md)
|
||||||
|
- 9.6 [为自定义包使用 godoc](09.6.md)
|
||||||
- 第10章:结构(struct)与方法(method)
|
- 第10章:结构(struct)与方法(method)
|
||||||
- 第11章:接口(interface)与反射(reflection)
|
- 第11章:接口(interface)与反射(reflection)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user