golang常用标准库
目录
编码
bytes
包字节实现了操作字节片的功能。它类似于字符串包的功能。
bytes.buffer
Introduction to Streams and Buffers | by Uday Hiwarale | RunGo | Medium
encoding
encoding包定义了供其它包使用的可以将数据在字节水平和文本表示之间转换的接口。encoding/gob、encoding/json、encoding/xml三个包都会检查使用这些接口。因此,只要实现了这些接口一次,就可以在多个包里使用。标准包内建类型time.Time和net.IP都实现了这些接口。接口是成对的,分别产生和还原编码后的数据。
strconv
strconv包实现了基本数据类型和其字符串表示的相互转换。
-
Atoi
string类型转换成int类型
strconv.ParseInt(s,10,0)
-
Itoa
int转换成string
strconv.FromatInt(i,10)
-
ParaseType系列
将string转换成指定Type类型
b, err := strconv.ParseBool("true") f, err := strconv.ParseFloat("3.1415", 64) i, err := strconv.ParseInt("-2", 10, 64) u, err := strconv.ParseUint("2", 10, 64)
-
FormatType系列
将给定类型数据格式化为string类型数据的功能
s1 := strconv.FormatBool(true) s2 := strconv.FormatFloat(3.1415, 'E', -1, 64) s3 := strconv.FormatInt(-2, 16) s4 := strconv.FormatUint(2, 16)
strconv包中还有Append系列、Quote系列等函数。详细见官方标准库
strings
strings包实现了用于操作字符的简单函数。
方法基本与bytes包相同
text
scanner包提供对utf-8文本的token扫描服务。它会从一个io.Reader获取utf-8文本,通过对Scan方法的重复调用获取一个个token。为了兼容已有的工具,NUL字符不被接受。如果第一个字符是表示utf-8编码格式的BOM标记,会自动忽略该标记。
一般Scanner会跳过空白和Go注释,并会识别所有go语言规格的字面量。它可以定制为只识别这些字面量的一个子集,也可以识别不同的空白字符。
tabwriter包实现了写入过滤器(tabwriter.Writer),可以将输入的缩进修正为正确的对齐文本。
unicode
unicode 包提供了一些测试Unicode码点属性的数据和函数.
IO
io
io包提供了对I/O原语的基本接口。本包的基本任务是包装这些原语已有的实现(如os包里的原语),使之成为共享的公共接口,这些公共接口抽象出了泛用的函数并附加了一些相关的原语的操作。
bufio
bufio包实现了有缓冲的I/O。它包装一个io.Reader或io.Writer接口对象,创建另一个也实现了该接口,且同时还提供了缓冲和一些文本I/O的帮助函数的对象。
bufio包实现了带缓冲区的读写,是对文件读写的封装
前面说到开发者更喜欢使用更上层的读写方法,golang的bufio包除了实现带缓冲区的读写提高效率和稳定性外,还提供按行读方法,ioutil包提供了读取整个文件、写文件方法
bufio、ioutil包更多文件、目录读写详见官方标准库
ioutil
Package ioutil implements some I/O utility functions.
fmt
实现了类似C语言printf和scanf的格式化I/O。格式化动作(‘verb’)源自C语言但更简单。
输入与输出
-
常用输出函数
Print、Printf、Println:直接输出内容
Sprint、Sprintf、Sprintln:生成内容并返回字符串
Fprint:将内容输出到一个io.Writer接口类型的变量,经常用于写入文件
Errorf:根据format参数生成格式化字符串并返回一个包含该字符串的错误
fmt.Println("打开文件出错,err:", err)//输出带换行 s2 := fmt.Sprintf("name:%s,age:%d", name, age)//带格式生成并返回 fmt.Fprintf(fileObj, "往文件中写如信息:%s", name)//带格式写入文件 err := fmt.Errorf("这是一个错误")
-
常用占位符
占位符 说明 %v 值的默认格式表示 %+v 类似%v,但输出结构体时会添加字段名 %#v 值的golang语法表示 %T 打印值的类型 %% 百分号 %d 表示10进制数 %b 表示2进制数 %f 浮点数,有小数 %9.2f 宽度9,精度2 %e 科学计数法 %s 直接输出字符串或[]byte %q 该值对应的双引号括起来的go语法字符串字面值,必要时会采用安全的转义表示 %p 指针,表示未16进制,并加上前缀0x -
常用输入函数
Scan、Scanf、Scanln:可以在程序运行过程中从标准输入获取用户的输入。
Scanln比较常用:在终端扫描标准输入,以空格分隔,直到换行结束扫描
fmt.Scanln(&name, &age, &married) fmt.Printf("扫描结果 name:%s age:%d married:%t \n", name, age, married)
bufio.NewReader:获取完整输入内容
FScan、Fscanf、Fscanln:从文件中获取输入
Sscan、Sscanf、Sscanln:从字符串获取输入
-
其他
- 实现goStringer的goString方法的结构体,可以改变结构体的打印输出,使用go的语法输出,如何输出取决于goString方法 fmt package - fmt - Go Packages - GoStringer
- 实现stringer的string方法的结构体,可以把结构体作为string输出,如何输出取决于string方法
网络
net
net包提供了可移植的网络I/O接口,包括TCP/IP、UDP、域名解析和Unix域socket。
net/http
http包提供了HTTP客户端和服务端的实现.
Go语言内置的net/http包十分的优秀,提供了HTTP客户端和服务端的实现
-
客户端
resp, err := http.Get("http://www.baidu.com/") resp, err := http.Post("http://www.9ong.com/post", "image/jpeg", &buf) resp, err := http.PostForm("http://www.9ong.com/form", url.Values{"key": {"Value"}, "id": {"123"}}) if err != nil { // handle error } //使用完response后必须关闭回复的主体 defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body)
使用完response后必须关闭回复的主体,总是会有不完美的地方存在哈,还需要自己关闭Body,从编码的角度看。
-
带参数的请求
带参数get请求
apiUrl := "http://127.0.0.1:9090/get" // URL param data := url.Values{} data.Set("name", "枯藤") data.Set("age", "18") u, err := url.ParseRequestURI(apiUrl) if err != nil { fmt.Printf("parse url requestUrl failed,err:%v\n", err) } u.RawQuery = data.Encode() // URL encode fmt.Println(u.String()) resp, err := http.Get(u.String()) if err != nil { fmt.Println("post failed, err:%v\n", err) return }
带参数post请求
// 表单数据 //contentType := "application/x-www-form-urlencoded" //data := "name=jm&age=20" // json contentType := "application/json" data := `{"name":"jm","age":20}` resp, err := http.Post(url, contentType, strings.NewReader(data))
看完以下的编写方式,我们觉得应该有更舒适第三方http库,只需要:
http.Get(url,json对象参数|结构体参数) http.Post(url,options,data) //options负责设置http头等信息,data是参数json对象或结构体
-
服务端
// http server func sayHello(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Hello world") } func main() { http.HandleFunc("/", sayHello) err := http.ListenAndServe(":9527", nil) if err != nil { fmt.Printf("http server failed, err:%v\n", err) return } }
自定义server
s := &http.Server{ Addr: ":9527", Handler: myHandler, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, MaxHeaderBytes: 1 << 20, } log.Fatal(s.ListenAndServe())
net/mail
mail 包实现了解析邮件消息的功能
net/rpc
rpc 包提供了一个方法来通过网络或者其他的I/O连接进入对象的外部方法
net/smtp
smtp包实现了简单邮件传输协议(SMTP),参见RFC 5321
net/textproto
textproto实现了对基于文本的请求/回复协议的一般性支持,包括HTTP、NNTP和SMTP
net/url
url包解析URL并实现了查询的逸码,参见RFC 3986
html
html包提供了用于转义和解转义HTML文本的函数。内含template包
模板-template包
html/template包实现了数据驱动的模板,用于生成可对抗代码注入的安全HTML输出。
-
模板语法
{{.}}
模板语法都包含在{{和}}中间,其中{{.}}中的点表示当前对象。
当我们传入一个结构体对象时,我们可以根据.来访问结构体的对应字段。例如:
type UserInfo struct { Name string Gender string Age int } func sayHello(w http.ResponseWriter, r *http.Request) { // 解析指定文件生成模板对象 tmpl, err := template.ParseFiles("./hello.html") if err != nil { fmt.Println("create template failed, err:", err) return } user := UserInfo{ Name: "枯藤", Gender: "男", Age: 18, } // 利用给定数据渲染模板,并将结果写入w tmpl.Execute(w, user) }
.表示当前对象/结构体user(w只是服务端的一个变量,也保存了user这个结构体而已)
<body> <p>Hello {{.Name}}</p> <p>性别:{{.Gender}}</p> <p>年龄:{{.Name}}</p> </body>
-
模板注释
{{/* a comment */}} 注释,执行时会忽略。可以多行。注释不能嵌套,并且必须紧贴分界符始止。
-
管道pipeline
Go的模板语法中支持使用管道符号|链接多个命令,用法和unix下的管道类似:|前面的命令会将运算结果(或返回值)传递给后一个命令的最后一个位置。
-
Actions
以下这些动作基本包含golang模板中常用的动作与含义说明
{{/* a comment */}} 注释,执行时会忽略。可以多行。注释不能嵌套,并且必须紧贴分界符始止,就像这里表示的一样。 {{pipeline}} pipeline的值的默认文本表示会被拷贝到输出里。 {{if pipeline}} T1 {{end}} 如果pipeline的值为empty,不产生输出,否则输出T1执行结果。不改变dot的值。 Empty值包括false、0、任意nil指针或者nil接口,任意长度为0的数组、切片、字典。 {{if pipeline}} T1 {{else}} T0 {{end}} 如果pipeline的值为empty,输出T0执行结果,否则输出T1执行结果。不改变dot的值。 {{if pipeline}} T1 {{else if pipeline}} T0 {{end}} 用于简化if-else链条,else action可以直接包含另一个if;等价于: {{if pipeline}} T1 {{else}}{{if pipeline}} T0 {{end}}{{end}} {{range pipeline}} T1 {{end}} pipeline的值必须是数组、切片、字典或者通道。 如果pipeline的值其长度为0,不会有任何输出; 否则dot依次设为数组、切片、字典或者通道的每一个成员元素并执行T1; 如果pipeline的值为字典,且键可排序的基本类型,元素也会按键的顺序排序。 {{range pipeline}} T1 {{else}} T0 {{end}} pipeline的值必须是数组、切片、字典或者通道。 如果pipeline的值其长度为0,不改变dot的值并执行T0;否则会修改dot并执行T1。 {{template "name"}} 执行名为name的模板,提供给模板的参数为nil,如模板不存在输出为"" {{template "name" pipeline}} 执行名为name的模板,提供给模板的参数为pipeline的值。 {{with pipeline}} T1 {{end}} 如果pipeline为empty不产生输出,否则将dot设为pipeline的值并执行T1。不修改外面的dot。 {{with pipeline}} T1 {{else}} T0 {{end}} 如果pipeline为empty,不改变dot并执行T0,否则dot设为pipeline的值并执行T1。
-
比较
eq 如果arg1 == arg2则返回真 ne 如果arg1 != arg2则返回真 lt 如果arg1 < arg2则返回真 le 如果arg1 <= arg2则返回真 gt 如果arg1 > arg2则返回真 ge 如果arg1 >= arg2则返回真
{{eq arg1 arg2 arg3}}
-
嵌套模板
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>tmpl test</title> </head> <body> <h1>测试嵌套template语法</h1> <hr> {{template "ul.html"}} <hr> {{template "ol.html"}} </body> </html> {{ define "ol.html"}} <h1>这是ol.html</h1> <ol> <li>AA</li> <li>BB</li> <li>CC</li> </ol> {{end}}
ul.html模板 不在当前html文档内,需要通过服务端template.ParseFiles指定加载的模板页,才能使用(有点耦合,要是都由前端模板文件去include包含模板可能会更自然些)
func tmplDemo(w http.ResponseWriter, r *http.Request) { tmpl, err := template.ParseFiles("./t.html", "./ul.html") if err != nil { fmt.Println("create template failed, err:", err) return } user := UserInfo{ Name: "枯藤", Gender: "男", Age: 18, } tmpl.Execute(w, user) }
mime
mime实现了MIME的部分规定
数据结构与算法
container
heap堆操作, list双向链表,ring环形链表
index
索引算法,如 suffixarrayb包通过使用内存中的后缀树实现了对数级时间消耗的子字符串搜索
math
math 包提供了基本常数和数学函数,如big,cmplx,rand。
sort
sort 包为切片及用户定义的集合的排序操作提供了原语
regexp
regexp包实现了正则表达式搜索
context
包上下文定义了 Context 类型,它携带跨越 API 边界和进程之间的截止日期、取消信号和其他请求范围的值。
在 Go http包的Server中,每一个请求在都有一个对应的 goroutine 去处理。请求处理函数通常会启动额外的 goroutine 用来访问后端服务,比如数据库和RPC服务。用来处理一个请求的 goroutine 通常需要访问一些与请求特定的数据,比如终端用户的身份认证信息、验证相关的token、请求的截止时间。 当一个请求被取消或超时时,所有用来处理该请求的 goroutine 都应该迅速退出,然后系统才能释放这些 goroutine 占用的资源。
介绍goroutine时,我们看到范例并没有在main函数里使用context,goroutine也会自动退出。原因是只有一种情况正在运行的goroutine会因为其他goroutine的结束被终止,就是main函数的退出或程序停止执行.
sync.WaitGroup解决了协程协同同步完成问题,context主要为了解决协程协同取消问题
-
Context接口
context.Context是一个接口,该接口定义了四个需要实现的方法
type Context interface { Deadline() (deadline time.Time, ok bool) //返回当前Context被取消的时间,也就是完成工作的截止时间 Done() <-chan struct{} //返回一个Channel,这个Channel会在当前工作完成或者上下文被取消之后关闭,多次调用Done方法会返回同一个Channel Err() error //返回当前Context结束的原因 Value(key interface{}) interface{} //从Context中返回键对应的值,对于同一个上下文来说,多次调用Value 并传入相同的Key会返回相同的结果,该方法仅用于传递跨API和进程间跟请求域的数据 }
注意:以下介绍的都是函数,并不是创建后context上下问对像的方法,而是context包的函数
-
context.Background函数
-
context.TODO函数
Go内置两个函数:Background()和TODO(),这两个函数分别返回一个实现了
Context接口
的background和todo。我们代码中最开始都是以这两个内置的上下文对象作为最顶层的partent context,衍生出更多的子上下文对象。Background()主要用于main函数、初始化以及测试代码中,作为Context这个树结构的最顶层的Context,也就是根Context。
TODO(),它目前还不知道具体的使用场景,如果我们不知道该使用什么Context的时候,可以使用这个。
background和todo本质上都是emptyCtx结构体类型,是一个不可取消,没有设置截止时间,没有携带任何值的Context。
-
context.withCancel函数
WithCancel返回带有新Done通道的父节点的副本。当调用返回的cancel函数或当关闭父上下文的Done通道时,将关闭返回上下文的Done通道,无论先发生什么情况。
func gen(ctx context.Context) <-chan int { dst := make(chan int) n := 1 go func() { for { select { case <-ctx.Done(): return // return结束该goroutine,防止泄露 case dst <- n: n++ } } }() return dst } func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() // 当我们取完需要的整数后调用cancel for n := range gen(ctx) { fmt.Println(n) if n == 5 { break } } }
-
context.withDeadline函数
返回父上下文的副本,并将deadline调整为不迟于d。如果父上下文的deadline已经早于d,则WithDeadline(parent, d)在语义上等同于父上下文。当截止日过期时,当调用返回的cancel函数时,或者当父上下文的Done通道关闭时,返回上下文的Done通道将被关闭,以最先发生的情况为准。
func main() { d := time.Now().Add(50 * time.Millisecond) ctx, cancel := context.WithDeadline(context.Background(), d) // 尽管ctx会过期,但在任何情况下调用它的cancel函数都是很好的实践。 // 如果不这样做,可能会使上下文及其父类存活的时间超过必要的时间。 defer cancel() select { case <-time.After(1 * time.Second): fmt.Println("overslept") case <-ctx.Done(): fmt.Println(ctx.Err()) } }
-
context.WithTimeout函数
func main() { // 设置一个50毫秒的超时 ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50) wg.Add(1) go worker(ctx) time.Sleep(time.Second * 5) cancel() // 通知子goroutine结束 wg.Wait() fmt.Println("over") }
-
context.WithValue函数
WithValue返回父节点的副本,其中与key关联的值为val。
仅对API和进程间传递请求域的数据使用上下文值,而不是使用它来传递可选参数给函数。
type TraceCode string func worker(){ ... key := TraceCode("TRACE_CODE") traceCode, ok := ctx.Value(key).(string) // 在子goroutine中获取trace code ... } func main(){ ... // 在系统的入口中设置trace code传递给后续启动的goroutine实现日志数据聚合 ctx = context.WithValue(ctx, TraceCode("TRACE_CODE"), "2009") wg.Add(1) go worker(ctx) ... }
-
关于cancel()函数
以上范例中的cancel函数,是通过context.With*系列函数返回得到的第二个值,用于通知同一个context下的所有goroutine结束/取消。
golang的context设计,让我们明白一个道理,能简单处理好一个问题,就是好的解决方案,没有高贵之分。
数据压缩与加密
archive
tar zip档案文件的存取
compress
bzip2,deflate,gzip,Lempel-Ziv-Welch,zlib数据格式解压缩
crypto
crypto包搜集了常用的密码(算法)常量
hash
hash包提供hash函数的接口
encoding
encoding包定义了供其它包使用的可以将数据在字节水平和文本表示之间转换的接口。encoding/gob、encoding/json、encoding/xml三个包都会检查使用这些接口。因此,只要实现了这些接口一次,就可以在多个包里使用。标准包内建类型time.Time和net.IP都实现了这些接口。接口是成对的,分别产生和还原编码后的数据。
json、xml、msgpack、base64、hex、gob、csv、pem、binary、base32、ascii85
json/xml
-
json
json可以和map、struct、interface相互转换
// 将struct、map转换成json 字符串 json.Marshal(struct|map) //将json字符串转换成Person结构体 type Person struct{ ... } jsonStr := []byte(`{"age":"18","name":"5lmh.com","marry":false}`) var p Person json.Unmarshal(jsonStr,&p)
弱类型的js、php可以随时动态自由的转换json字符串,这个确实舒服太多,怪不得php开发者总说数组强大。
-
xml
与json包的方法是一样,只是数据源不一样
xml.Marshal(struct|map) xml.Unmarshal(xmlStr,&p)
-
msgpack
MSGPack是二进制的json,性能更快,更省空间
需要安装第三方包:go get -u github.com/vmihailenco/msgpack
```go
msgpack.Marshal(struct|map)
msgpack.Unmarshal(msgpackbinary,&p)
```
数据持久化
database
sql包提供了保证SQL或类SQL数据库的泛用接口。
使用sql包时必须注入(至少)一个数据库驱动。参见http://golang.org/s/sqldrivers 获取驱动列表。
更多用法示例,参见wiki页面:http://golang.org/s/sqlwiki。
操作系统相关
os
os包提供了操作系统函数的不依赖平台的接口。设计为Unix风格的,虽然错误处理是go风格的;失败的调用会返回错误值而非错误码。通常错误值里包含更多信息。例如,如果某个使用一个文件名的调用(如Open、Stat)失败了,打印错误时会包含该文件名,错误类型将为*PathError,其内部可以解包获得更多信息。
os包的接口规定为在所有操作系统中都是一致的。非公用的属性可以从操作系统特定的syscall包获取
os包提供了Create、NewFile、Open、OpenFile、Remove方法
返回的文件对象,提供了读写方法,比如Write、WriteAt、WriteString、Read、ReadAt方法
-
文件打开与关闭
package main import ( "fmt" "os" ) func main() { // 只读方式打开当前目录下的main.go文件 file, err := os.Open("./main.go") if err != nil { fmt.Println("open file failed!, err:", err) return } // 关闭文件 file.Close() }
golang可以考虑再简化下文件的打开及异常的处理和关闭,python的with open简化了try异常和close的处理,让代码更简洁,编写者不用去关心异常处理和文件关闭处理代码,这本不属于业务逻辑代码,趋势应该是让语言或机器自动实现了
-
写文件
file.WriteString("ab\n") file.Write([]byte("cd\n"))
我们会更新一篇关于byte与string区别的文章
-
读文件
golang文件读取可以用file.Read()和file.ReadAt(),读到文件末尾会返回io.EOF的错误,EOF这是大部分语言读取结尾的标识符了
golang的os包的读写还需要偏上层封装,不要让开发者去了解这么多读写的原理,比如读取一行、整个文件,这些是开发者更乐意用到的,不用关心读写的原理,至于性能开发者会认为是语言要解决的问题,当然当我们有足够经验以后,就可以使用更底层些的方法来实现,提高性能。如果硬件的发展更快,我们更希望大家都可以不关心底层实现的去使用更上层的方法
package main import ( "fmt" "io" "os" ) func main() { // 打开文件 file, err := os.Open("./xxx.txt") if err != nil { fmt.Println("open file err :", err) return } defer file.Close() // 定义接收文件读取的字节数组 var buf [128]byte var content []byte for { n, err := file.Read(buf[:]) if err == io.EOF { // 读取结束 break } if err != nil { fmt.Println("read file err ", err) return } content = append(content, buf[:n]...) } fmt.Println(string(content)) }
path
flag
命令行参数解析-flag包
flag包是的golang开发命令行工具更为简单。
看一个完整示例,我们就更清楚flag的用途了:
执行命令时要求输入4个参数,并指定了参数的类型与默认值
func main() {
//定义命令行参数方式1
var name string
var age int
var married bool
var delay time.Duration
flag.StringVar(&name, "name", "张三", "姓名")
flag.IntVar(&age, "age", 18, "年龄")
flag.BoolVar(&married, "married", false, "婚否")
flag.DurationVar(&delay, "d", 0, "延迟的时间间隔")
//解析命令行参数
flag.Parse()
fmt.Println(name, age, married, delay)
//返回命令行参数后的其他参数
fmt.Println(flag.Args())
//返回命令行参数后的其他参数个数
fmt.Println(flag.NArg())
//返回使用的命令行参数个数
fmt.Println(flag.NFlag())
}
首先flag提供了命令行help功能,执行命令行会给出相应提示:
$ ./flag_demo -help
Usage of ./flag_demo:
-age int
年龄 (default 18)
-d duration
时间间隔
-married
婚否
-name string
姓名 (default "张三")
其次flag提供命令行参数parse解析能力:
注意:Args()\NArg()\NFlag()的含义
$ ./flag_demo -name pprof --age 28 -married=false -d=1h30m
pprof 28 false 1h30m0s
[]
0
4
当然如果我们仅仅只是需要简单命令行输入的参数,我们也可以简单的考虑os.Args来获取命令行参数。
os.Args是一个存储命令行参数的字符串切片,它的第一个元素是执行文件的名称,这和大部分语言命令行模式是类似的(python、php等)
sync
sync包提供了基本的同步基元,如互斥锁。除了Once和WaitGroup类型,大部分都是适用于low-level程序线程,high-level的同步使用channel通信更好一些
time
time包提供了时间的显示和测量用的函数。日历的计算采用的是公历。
-
时间与日期转换
func timeDemo() { now := time.Now() //获取当前时间 fmt.Printf("current time:%v\n", now) year := now.Year() //年 month := now.Month() //月 day := now.Day() //日 hour := now.Hour() //小时 minute := now.Minute() //分钟 second := now.Second() //秒 fmt.Printf("%d-%02d-%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second) timestamp1 := now.Unix() //时间戳 timestamp2 := now.UnixNano() //纳秒时间戳 fmt.Printf("current timestamp1:%v\n", timestamp1) fmt.Printf("current timestamp2:%v\n", timestamp2) timeObj := time.Unix(timestamp1, 0)//时间戳转换成时间对象,再通过类似以上当前时间转换成时间格式 }
-
时间间隔(单位)
time包中时间间隔的定义:
const ( Nanosecond Duration = 1 Microsecond = 1000 * Nanosecond Millisecond = 1000 * Microsecond Second = 1000 * Millisecond Minute = 60 * Second Hour = 60 * Minute )
var _time = 10 * time.Second //10秒
例如:time.Duration表示1纳秒,time.Second表示1秒。
-
时间格式化
golang的常用时间格式化模板并不是常见的:Y-m-d H:i:s,而是2006-01-02 15:04 ,这是24小时制,2006-01-02 03:04 PM,则是12小时制
fmt.Println(now.Format("2006-01-02 15:04:05.000 Mon Jan")) // 12小时制 fmt.Println(now.Format("2006-01-02 03:04:05.000 PM Mon Jan")) fmt.Println(now.Format("2006/01/02 15:04")) fmt.Println(now.Format("15:04 2006/01/02")) fmt.Println(now.Format("2006/01/02"))
golang大佬,何必呢,增加跨语言语法记忆难度,虽然只是一点点,但如果其他地方也这样有’意思’,累计下难度就不小了。
-
时间操作
golang中的时间,并不是简单的数字加减,time包提供了实践操作的方法:
-
Add:时刻+时间段
func main() { now := time.Now() later := now.Add(time.Hour) // 当前时间加1小时后的时间 beforer := now.Add(-time.Hour) // 当前时间减1小时后的时间 fmt.Println(later) }
-
Sub:时刻1 - 时刻2,求两个时间的差值,注意这里并不是(时刻-时间段)的实现,(时刻-时间段)仍然可以用Add(-时间段)来实现
-
Equal:判断时间是否相等,会考虑时区
-
Before:判断是否在某个时刻之前
-
After:判断是否在某个时刻之后
-
-
定时器
定时器,本质上是一个channel,golang中使用time.Ticker(duration)来设置定时器
-
一次性定时器(延时)
package main import ( "fmt" "time" ) func main() { /* 用sleep实现定时器 */ fmt.Println(time.Now()) time.Sleep(time.Second) fmt.Println(time.Now()) /* 用timer实现定时器 */ timer := time.NewTimer(time.Second) fmt.Println(<-timer.C) /* 用after实现定时器 */ fmt.Println(<-time.After(time.Second)) }
-
周期性定时器
func tickDemo() { ticker := time.Tick(time.Second) //定义一个1秒间隔的定时器 //ticker := time.NewTicker(time.Second) for i := range ticker { fmt.Println(i)//每秒都会执行的任务 } }
-
syscall
包 syscall 包含低级操作系统原语的接口
调试与测试
errors
error 包实现了用于错误处理的函数
debug
error 包实现了用于错误处理的函数
log
log包实现了简单的日志服务与系统日志服务的接口
官方标准简单log包,功能有限,更多可以实现流水账的日志记录,如果我们需要更多比如不同级别的日志记录,可以选择第三方日志库:logrus、zap等
//使用标准日志log,设置日志输出到xx.log文件,设置flags支持文件名、行号、日志前缀、时间格式
func main() {
logFile, err := os.OpenFile("./xx.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
fmt.Println("open log file failed, err:", err)
return
}
log.SetOutput(logFile)
log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate)
log.SetPrefix("[JM]")
log.Println("这里记录一条日志。")
}
[JM]2020/01/14 15:32:45.431506 .../log_demo/main.go:13: 这里记录一条日志。
testing
包测试为 Go 包的自动化测试提供支持
golang运行时与自举
runtime
reflect
reflect包实现了运行时反射,允许程序操作任意类型的对象。典型用法是用静态类型interface{}保存一个值,通过调用TypeOf获取其动态类型信息,该函数返回一个Type类型值。调用ValueOf函数返回一个Value类型值,该值代表运行时的数据。Zero接受一个Type类型参数并返回一个代表该类型零值的Value类型值。
参见"The Laws of Reflection"获取go反射的介绍:http://golang.org/doc/articles/laws_of_reflection.html
反射是指在程序运行期对程序本身进行访问和修改的能力
reflect包封装了反射相关的方法:
获取类型信息:reflect.TypeOf,是静态的
获取值信息:reflect.ValueOf,是动态的
反射可以获取interface类型信息、获取值信息、修改值信息
反射可以查看结构体字段、类型、方法,修改结构体的值,调用方法
-
空接口结合反射
可以通过 空接口 可以表示任何参数,利用反射判断参数类型
builtin
builtin 包为Go的预声明标识符提供了文档。此处列出的条目其实并不在builtin 包中,对它们的描述只是为了让 godoc 给该语言的特殊标识符提供文档
go
go自举编译器
unsafe
unsafe包提供了一些跳过go语言类型安全限制的操作
其他
expvar
expvar包提供了公共变量的标准接口,如服务的操作计数器。本包通过HTTP在/debug/vars位置以JSON格式导出了这些变量。
对这些公共变量的读写操作都是原子级的。
image
image实现了基本的2D图片库。
基本接口叫作Image。图片的色彩定义在image/color包。
Image接口可以通过调用如NewRGBA和NewPaletted函数等获得;也可以通过调用Decode函数解码包含GIF、JPEG或PNG格式图像数据的输入流获得。解码任何具体图像类型之前都必须注册对应类型的解码函数。
plugin
go插件化
参考
转载请标注来源:9ong@TsingChan