Go中的标准库严格遵守向后兼容的承诺,不用担心程序无法兼容不同的GO语言版本,也不用管理第三方依赖。GO很稳定和可靠 Go的包提供了其他语言开发者的无法做到的事情。
记录日志
即便没有表现出来,我的程序依旧可能由BUG。日志是一种找到这些BUG,更好的了解它工作状态的方法。日志是程序员的眼睛和耳朵
log包
log关联的标志
const(
//日期: 2009/01/23
Ldate = 1 << iota //1 << 0
//时间 15:00:33
Ltime //1 << 1
//毫秒级别时间
Lmicroseconds //1 << 2
//完整的路径,文件名,行号
Llongfile //1 << 3
//只包含文件名和行号
Lshortfile //1 << 4
LstdFlags = Ldate | Ltime
)
iota在常量声明区中有特殊的作用:这个关键字为每个常量都复制相同的计算公式,直到声明区结束或遇到下一个计算表达式。此外iota是递增的,==每次处理完后会自增1==,初始值是0.
为每一个常量赋予一个独立的位,这样的话,进行对位与操作相当于把他们组合起来,传入log.SetFlags()函数。之后log包会按位检查这个整数值,按照需求设置日志项的信息。
func main(){
log.Println("message") //写日志的标准写法
log.Fatalln("fatal message")//fatal系列会写完日志消息后调用os.Exit(1)
log.Panicln("Panic message")// Panic系列会写完日志消息后处罚一个Panic ,打印调用栈后终止。
}
Log包的日志记录器是多goroutine安全的,这意味着在多个goroutine中可以同时调用来自同一个日志记录器的这些函数,他们彼此之间不会有写冲突
定制日志记录器
需要建立一个Logger指针类型值,可以给每一个日志记录器配置一个单独的目的地,并独立设置其前缀和标志
func init(){
file,err := os.OpenFile("errors.txt",os.O_CREATE|os.O_WRONLY|os.O_APPEND,0666)
if err != nil{
log.Fatalln("Failed to open error log File:",err)
}
Warning = log.New(os.Stdout,
"TRACE:",
log.Ldate|log.Ltime|log.Lshortfile)
//使用New函数正确初始化logger,第一个参数out指定了日志要写到的目的地,这个参数必须实现io.Writer接口。第二个参数是prefix,定义前缀,标志是最后一个参数
//Stdin,Stdout,Stderr 三个变量都是指向三个文件描述符的File指针, File指针是实现了IO.Writer指针的
Error = log.New(io.MultiWriter(file,os.Stderr),
"Error:",
log.Ldate|log.Ltime|log.Lshortfile)
// io.MultiWriter(file ...io.Writer)
// 这个函数会返回一个io.Writer接口类型的值,这个值包含了所有参数。这个值会把所有传入的io.Writer值绑定在一起。对这个值写入时,会对所有绑在一起的值写入。
// 它的存在允许同时向多个地方写输出。
}
func main(){
Warning.Println("There are something that you should konw ")
Error.Println("Someting is failed")
}
编码解码
解码Json(使用NewDecoder)
type (
// gResult maps to the result document received from the search.
gResult struct {
GsearchResultClass string `json:"GsearchResultClass"`
UnescapedURL string `json:"unescapedUrl"`
URL string `json:"url"`
VisibleURL string `json:"visibleUrl"`
CacheURL string `json:"cacheUrl"`
Title string `json:"title"`
TitleNoFormatting string `json:"titleNoFormatting"`
Content string `json:"content"`
}
// gResponse contains the top level document.
gResponse struct {
ResponseData struct {
Results []gResult `json:"results"`
} `json:"responseData"`
}
)
把Json解码成结构体方便我们使用数据。
``是结构体标签字段,最常见的用途之一是在处理JSON数据时,指定JSON键名。如果不存在标签,编码和解码过程就会试图通过大小写无关的方式直接用字段名匹配。如果无法匹配对应的字段就是零值。
func main() {
uri := "http://ajax.googleapis.com/ajax/services/search/web?v=1.0&rsz=8&q=golang"
// Issue the search against Google.
resp, err := http.Get(uri) // http请求 得到json数据
if err != nil {
log.Println("ERROR:", err)
return
}
defer resp.Body.Close()
// Decode the JSON response into our struct type.
var gr gResponse
err = json.NewDecoder(resp.Body).Decode(&gr)
if err != nil {
log.Println("ERROR:", err)
return
}
}
NewDecoder其实是返回一个Decoder类型的指针,这个类型有Decode方法。 但是由于GO中支持复合语句调用,即可以直接调用Newcoder函数返回值的Decode方法,而不把这个值存入变量。
==任何类型都实现了空接口,这意味者用空接口当参数的函数接收任何类型的值==
有时需要处理的JSON文档会以string的方式存在,这种情况下,需要将string转换成byte切片,并使用json包中的Unmarshal函数进行反序列化处理。
var c Contact // 定义好的解码格式的json结构体。
err := json.Unimalshal([]byte(JSON),&c)
有时,我们无法为JSON格式声明一个结构类型,而是需要更灵活的方式处理Json数据(假设我们有一个JSON文档,其结构是动态的,即我们无法预先知道所有的字段和嵌套结构。例如,我们可能从不同的API接收数据,每个API返回的JSON结构略有不同),我们可以把Json文档解码到map变量中。 同样也是先转换成字节切片在使用Unimalshal()
var c make(map[string]interface{}) // 定义好的解码格式的json结构体。
err := json.Unimalshal([]byte(JSON),&c)
这也有很大的坏处,处理起来很麻烦。因为需要将值转换成合适的类型。
编码JSON
使用Json包中的MarshalIndent函数进行编码。这个函数能很方便的将GO语言的map类型或结构体类型转换成容易读的JSON类型。
==序列化是将数据转换成JSON字符串的过程==
IO包
GO中的IO包借鉴了UNIX系统的理念:一个程序的输出可以是另一个程序的输入。这个包可以高效处理数据,不用考虑数据是什么,数据来自哪儿等问题。
实现了io.Writer 或 io.Reader两个接口的类型的值都可以使用io包的所有功能。
Writer接口和Reader接口
type Writer interface{
Write(p []byte) (n int,err error)
}
在Write方法中试图在p切片中插入len(p)长度的数据,如果无法全部写入就报错。==不管什么情况,都不能改写切片里面的数据,哪怕是临时都不行==
type Reader interface{
Read(p []byte)(n int, err error)
}
- Read的方法的目的是读取数据填满这个p切片,允许出现读到的数据大小小于len(p)。当读到的数据小于len(P)时,read不应该阻塞以等待足够多的数据而是直接返回
- 当文件读到文件末尾EOF符号时,有两个合理的方法,是直接返回已经读的字节数,而且返回EOF错误。第二种是返回nil错误,但是下一次返回就是长度为0,错误为EOF
- 给调用Read的人的建议,我们应该任何时候先处理返回的字节数,再去管理返回的错误值。
- Read方法不应该同时返回长度0和nil错误
Stdin,Stdout,Stderr 三个变量都是指向三个文件描述符的File指针, File指针是实现了IO.Writer接口的
我们可以仅仅使用io http os 包实现linux中的curl程序。
package main
import(
"io"
"log"
"net/http"
"os"
)
func main(){
r,err := http.Get(os.Args[1])
if err != nil{
log.Fatalln("http err : ",err)
}
file,err := os.Create(os.Args[2])
if err != nil{
log.Fatalln("File err : ",err)
}
defer file.Close()
//使用MultiWriter把输入绑定在一起
dest := io.MultiWriter(os.Stdout,file)
io.Copy(dest,r.Body)
if err := r.Body.Close(); err != nil{
log.Println(err)
}
}