Go:package
文章目录
- 标准库概述
- regexp包
- 锁和sync包
- 自定义包和可见性
- 基本格式
- 导入外部安装包
- 包的初始化
- 自定义包使用godoc
- 自定义包的目录结构
标准库概述
在之前的部分已经用了很多和标准库有关的内容,比如有fmt,os这种功能
- unsafe: 包含了一些打破 Go 语言“类型安全”的命令,一般的程序中不会被使用,可用在 C/C++ 程序的调用中
- syscall-os-os/exec:
- os: 提供给我们一个平台无关性的操作系统功能接口,采用类 Unix 设计,隐藏了不同操作系统间的差异,让不同的文件系统和操作系统对象表现一致
- os/exec: 提供我们运行外部操作系统命令和程序的方式
- syscall: 底层的外部包,提供了操作系统底层调用的基本接口
regexp包
正则表达式常用于字符串中进行一些配置的匹配,例如
func test1() {
//目标字符串
searchIn := "John: 2578.34 William: 4567.23 Steve: 5632.18"
pat := "[0-9]+.[0-9]+" //正则
f := func(s string) string {
v, _ := strconv.ParseFloat(s, 32)
return strconv.FormatFloat(v*2, 'f', 2, 32)
}
if ok, _ := regexp.Match(pat, []byte(searchIn)); ok {
fmt.Println("Match Found!")
}
re, _ := regexp.Compile(pat)
//将匹配到的部分替换为"##.#"
str := re.ReplaceAllString(searchIn, "##.#")
fmt.Println(str)
//参数为函数时
str2 := re.ReplaceAllStringFunc(searchIn, f)
fmt.Println(str2)
}
锁和sync包
在一些复杂的程序中,通常通过不同线程执行不同应用来实现程序的并发。当不同线程要使用同一个变量时,经常会出现一个问题:无法预知变量被不同线程修改的顺序!(这通常被称为资源竞争,指不同线程对同一变量使用的竞争)显然这无法让人容忍,那我们该如何解决这个问题呢
经典的做法是一次只能让一个线程对共享变量进行操作。当变量被一个线程改变时(临界区),我们为它上锁,直到这个线程执行完成并解锁后,其他线程才能访问它
在之前的map中,由于性能的原因,它实际上并不是现成安全的,所以在并行访问一个共享的map资源的时候,实际上是会出现错误
而在Go语言中,这种锁的机制是通过sync包中的锁来完成的,这意味着线程将会以有序的对同一个变量进行访问
sync.Mutex 是一个互斥锁,它的作用是守护在临界区入口来确保同一时间只能有一个线程进入临界区
因此可以有下面的例子,假设有一个共享资源需要被保护,那么就可以借助锁来进行对应的保护
// 定义需要保护起来的成员
type test2Info struct {
mu sync.Mutex
str string
}
func test2Update(i *test2Info) {
i.mu.Lock()
i.str = "hello go"
i.mu.Unlock()
}
func test2() {
// 现在要对这个str进行修改,那么就需要先加锁,再解锁
var i test2Info
test2Update(&i)
}
相对简单的情况下,通过使用 sync 包可以解决同一时间只能一个线程访问变量或 map 类型数据的问题。如果这种方式导致程序明显变慢或者引起其他问题,我们要重新思考来通过 goroutines 和 channels 来解决问题,这是在 Go 语言中所提倡用来实现并发的技术
自定义包和可见性
基本格式
import 的一般格式如下:
import "包的路径或 URL 地址"
导入外部安装包
如果你要在你的应用中使用一个或多个外部包,首先你必须使用go install在你的本地机器上安装它们
假设你想使用 http://codesite.ext/author/goExample/goex 这种托管在 Google Code、GitHub 和 Launchpad 等代码网站上的包
通过如下命令安装:
go install codesite.ext/author/goExample/goex
将一个名为 codesite.ext/author/goExample/goex 的 map 安装在 $GOROOT/src/ 目录下
通过以下方式,一次性安装,并导入到你的代码中:
import goex "codesite.ext/author/goExample/goex"
因此该包的 URL 将用作导入路径
包的初始化
程序的执行开始于导入包,初始化 main 包然后调用 main() 函数
一个没有导入的包将通过分配初始值给所有的包级变量和调用源码中定义的包级 init() 函数来初始化。一个包可能有多个 init() 函数甚至在一个源码文件中。它们的执行是无序的。这是最好的例子来测定包的值是否只依赖于相同包下的其他值或者函数
init() 函数是不能被调用的
导入的包在包自身初始化前被初始化,而一个包在程序执行中只能初始化一次
自定义包使用godoc
godoc在显示自定义包中的注释也有很好的效果:注释必须以 // 开始并无空行放在声明(包,类型,函数)前。godoc 会为每个文件生成一系列的网页
自定义包的目录结构
/home/user/goprograms
ucmain.go (uc 包主程序)
Makefile (ucmain 的 makefile)
ucmain
src/uc (包含 uc 包的 go 源码)
uc.go
uc_test.go
Makefile (包的 makefile)
uc.a
_obj
uc.a
_test
uc.a
bin (包含最终的执行文件)
ucmain
pkg/linux_amd64
uc.a (包的目标文件)