go标准库二 | 青训营笔记

96 阅读3分钟

这是我参与「第五届青训营」伴学笔记创作活动的第9天。

log

  • golang内置了log包,实现简单的日志服务。通过调用log包的函数,可以实现简单的日志打印功能。
  • log包中有3个系列的日志打印函数,分别print系列、panic系列、fatal系列。
函数系列作用
print单纯打印日志
panic打印日志,抛出panic异常
fatal打印日志,强制结束程序(os.Exit(1)),defer函数不会执行

log配置

标准log配置

  • 默认情况下log只会打印出时间,但是实际情况下可能还需要获取文件名,行号等信息,log包提供定制的接口。 log包提供两个标准log配置的相关方法:
func Flags() int  // 返回标准log输出配置
func SetFlags(flag int)  // 设置标准log输出配置
  • flag参数
const (
    // 控制输出日志信息的细节,不能控制输出的顺序和格式。
    // 输出的日志在每一项后会有一个冒号分隔:例如2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message
    Ldate         = 1 << iota     // 日期:2009/01/23
    Ltime                         // 时间:01:23:23
    Lmicroseconds                 // 微秒级别的时间:01:23:23.123123(用于增强Ltime位)
    Llongfile                     // 文件全路径名+行号: /a/b/c/d.go:23
    Lshortfile                    // 文件名+行号:d.go:23(会覆盖掉Llongfile)
    LUTC                          // 使用UTC时间
    LstdFlags     = Ldate | Ltime // 标准logger的初始值
)
  • 标准日志配置
package main

import (
	"fmt"
	"log"
)

func main() {
	i := log.Flags()
	fmt.Printf("i: %v\n", i)
	log.SetFlags(log.Ldate | log.Ltime | log.Llongfile)
	log.Print("my log")
}

日志前缀配置

  • log包提供两个日志前缀配置的相关函数:
func Prefix() string  // 返回日志的前缀配置
func SetPrefix(prefix string)  // 设置日志前缀
package main

import (
	"fmt"
	"log"
)

func main() {
	s := log.Prefix()
	fmt.Printf("s: %v\n", s)
	log.SetPrefix("MyLog: ")
	s = log.Prefix()
	fmt.Printf("s: %v\n", s)
	log.Print("my log...")
}

日志输出位置配置

  • golang的log包支持将日志输出到文件中。log包提供了func SetOutput(w io.Writer)函数,将日志输出到文件中。
package main

import (
	"log"
	"os"
)

func main() {
	f, err := os.OpenFile("a.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		log.Panic("打开日志文件异常")
	}
	log.SetOutput(f)
	log.Print("my log...")
}

自定义logger

  • log包中提供了func New(out io.Writer, prefix string, flag int) *Logger函数来实现自定义logger。
var logger *log.Logger

func init()  {
    logFile, err := os.OpenFile("a.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
    if err != nil {
        log.Panic("打开日志文件异常")
    }
    logger = log.New(logFile, "success", log.Ldate | log.Ltime | log.Lshortfile)
}
func main() {
    logger.Println("自定义logger")
}

builtin

  • 提供了一些类型声明、变量和常量声明,还有一些函数,builtin包不需要导入,相关变量和函数就可以直接使用。

常用函数

  • append
func append(slice []Type, elems ...Type) []Type

slice = append(slice, elem1, elem2)  //直接在slice后面添加单个元素,添加元素类型可以和slice相同,也可以不同
slice = append(slice, anotherSlice...)  //直接将另外一个slice添加到slice后面,但其本质还是将anotherSlice中的元素一个一个添加到slice中,和第一种方式类似.(...表示将数组元素打散)
  • len:返回数组、切片、字符串、通道的长度
  • print、println:打印输出到控制台
  • panic:抛出一个panic异常
  • new和make
    • 区别:
      • make只能用来分配及初始化类型为slice,map,chan的数据;new可以分配任意类型的数据
      • new分配返回的是指针,即类型*T;make返回引用,即T;
      • new分配的空间被清零,make分配后,会进行初始化。

bytes

  • bytes包提供了对字节切片进行读写操作的一系列函数,字节切片处理的函数分为基本处理函数、比较函数、后缀检查函数、索引函数、分割函数、大小写处理函数和子切片处理函数等.
  • Contains:是否包含目标切片
  • Count:计数出现数量
  • Repeat:重复指定次数
  • Replace:指定位置替换
  • Runes:将中文等特殊符号进行转换
  • Join:拼接字符串

Buffer类型

  • 声明一个Buffer的四种方法:
var b bytes.Buffer // 直接定义一个Buffer变量,不用初始化,可以直接使用
 b := new(bytes.Buffer) //使用New返回Buffer变量
 b := bytes.NewBuffer(s []byte) //从一个[]byte切片,构造一个Buffer
 b := bytes.NewBufferString(s string) //从一个string变量,构造一个Buffer
  • 相关操作
 b.Write(d []byte) //将切片d写入Buffer尾部
 b.WriteString(s string) //将字符串s写入Buffer尾部
 b.WriteByte(c byte) //将字符c写入Buffer尾部
 b.WriteRune(r rune) //将一个rune类型的数据放到缓冲器的尾部
 b.WriteTo(w io.Writer) //将Buffer中的内容输出到实现了io.Writer接口的可写入对象中
 b.ReadFrom(i io.Reader) //将文件中的内容写入Buffer
 c := make([]byte,8)
 b.Read(c) //一次读取8个byte到c容器中,每次读取新的8个byte覆盖c中原来的内容
 b.ReadByte() //读取第一个byte,b的第1个byte被拿掉,赋值给 a => a, _ :=   b.ReadByte()
 b.ReadRune() //读取第一个rune,b的第1个rune被拿掉,赋值给 r =>  r, _  := b.ReadRune()
 b.ReadBytes(delimiter byte) //需要一个 byte作为分隔符 ,读的时候从缓冲器里找第一个出现的分隔符(delim),找到后,把从缓冲器头部开始到分隔符之间的所有byte进行返回,作为byte类型的slice,返回后,缓冲器也会空掉一部分
 b.ReadString(delimiter byte) // 需要一个byte作为分隔符,读的时候从缓冲器里找第一个出现的分隔符(delim),找到后,把从缓冲器头部开始到分隔符之间的所有byte进行返回, 作为字符串返回 ,返回后,缓冲器也会空掉一部分 b.ReadForm(i io.Reader) // 从一个实现io.Reader接口的r,把r里的内容读到缓冲器里 ,n 返回读的数量

Reader类型

  • Reader实现了 io.Reader, io.ReaderAt, io.WriterTo, io.Seeker,io.ByteScanner, io.RuneScanner接口,Reader是只读的、可以seek。

errors

  • errors包实现了操作错误的函数。使用 error 类型来返回函数执行过程中遇到的错误,如果返回的 error 值为 nil,则表示未遇到错误,否则 error 会返回一个字符串,用于说明遇到了什么错误。
  • error接口
    type error interface {
            Error() string
    }
  • 可以用任何类型去实现此接口,只要添加一个 Error() 方法即可。即 error 可以是任何类型。
  • error 不一定表示一个错误,它可以表示任何信息,比如 io 包中就用 error 类型的 io.EOF 表示数据读取结束,而不是遇到了错误。
  • errors 包实现了一个最简单的 error 类型,只包含一个字符串,它可以记录大多数情况下遇到的错误信息。errors 包的用法也很简单,只有一个 New 函数,用于生成一个最简单的 error 对象:
func New(text string) error
package main

import (
	"errors"
	"fmt"
)

func check(s string) error {
	if s == "" {
		return errors.New("字符串不能为空")
	} else {
		return nil
	}
}

func main() {
	check("hello")
	err := check("")
	fmt.Printf("err: %v\n", err.Error())
}

自定义错误

package main

import (
	"fmt"
	"time"
)
// MyError is an error implementation that includes a time and message.
type MyError struct {
	When time.Time
	What string
}

func (e MyError) Error() string {
	return fmt.Sprintf("%v: %v", e.When, e.What)
}

func oops() error {
	return MyError{
		time.Date(1989, 3, 15, 22, 30, 0, 0, time.UTC),
		"the file system has gone away",
	}
}
func main() {
	if err := oops(); err != nil {
		fmt.Println(err)
	}
}