为了账号安全,请及时绑定邮箱和手机立即绑定

Go语言开发(十一)、Go语言常用标准库一

标签:
Go

一、log

1、log模块简介

Go语言中log模块用于在程序中输出日志。

log模块提供了三类日志输出接口,Print、Fatal和Panic。Print是普通输出;Fatal是在执行完Print后,执行 os.Exit(1);Panic是在执行完Print后调用panic()方法。log模块对每一类接口其提供了3中调用方式,分别是"Xxxx、 Xxxxln、Xxxxf"。

2、log.Print接口

log.Print类接口包括log.Print、log.Println、log.Printf,接口如下:

// Printf calls l.Output to print to the logger.

// Arguments are handled in the manner of fmt.Printf.

func (l *Logger) Printf(format string, v ...interface{}) {

   l.Output(2, fmt.Sprintf(format, v...))

}

// Print calls l.Output to print to the logger.

// Arguments are handled in the manner of fmt.Print.

func (l *Logger) Print(v ...interface{}) { l.Output(2, fmt.Sprint(v...)) }

// Println calls l.Output to print to the logger.

// Arguments are handled in the manner of fmt.Println.

func (l *Logger) Println(v ...interface{}) { l.Output(2, fmt.Sprintln(v...)) }

log.Print类接口使用示例:

package main

import (

   "log"

)

func logPrintTest(){

   arr := []int {2,3}

   log.Print("Print array ",arr,"\n")

   log.Println("Println array",arr)

   log.Printf("Printf array with item [%d,%d]\n",arr[0],arr[1])

}

func main() {

   logPrintTest()

}

// output

// 2018/10/06 13:38:29 Print array [2 3]

// 2018/10/06 13:38:29 Println array [2 3]

// 2018/10/06 13:38:29 Printf array with item [2,3]

3、log.Fatal接口

log.Fatal类接口包括log.Fatal、log.Fatalln、log.Fatalf,接口如下:

// Fatal is equivalent to l.Print() followed by a call to os.Exit(1).

func (l *Logger) Fatal(v ...interface{}) {

   l.Output(2, fmt.Sprint(v...))

   os.Exit(1)

}

// Fatalf is equivalent to l.Printf() followed by a call to os.Exit(1).

func (l *Logger) Fatalf(format string, v ...interface{}) {

   l.Output(2, fmt.Sprintf(format, v...))

   os.Exit(1)

}

// Fatalln is equivalent to l.Println() followed by a call to os.Exit(1).

func (l *Logger) Fatalln(v ...interface{}) {

   l.Output(2, fmt.Sprintln(v...))

   os.Exit(1)

}

 log.Fata接口会先将日志内容打印到标准输出,接着调用系统的 os.exit(1)接口,退出程序并返回状态1 。但由于直接调用系统接口退出,defer函数不会被调用。

 log.Fatal接口使用示例:

package main

import (

   "log"

   "fmt"

)

func logFatalTest(){

   level := "Fatal"

   defer func() {

      fmt.Println("defer Fatal")

   }()

   log.Fatal("print ",level, " level\n")

   // 后续不会被执行

   log.Fatalln("print ",level)

   log.Fatalf("print %s level", level)

}

func main() {

   logFatalTest()

}

// output

// 2018/10/06 13:47:57 print Fatal level

 log.Fatal接口调用会导致程序退出。

4、log.Panic接口

log.Panic类接口包括log.Panic、log.Panicln、log.Panicf,接口如下:

// Panic is equivalent to l.Print() followed by a call to panic().

func (l *Logger) Panic(v ...interface{}) {

   s := fmt.Sprint(v...)

   l.Output(2, s)

   panic(s)

}

// Panicf is equivalent to l.Printf() followed by a call to panic().

func (l *Logger) Panicf(format string, v ...interface{}) {

   s := fmt.Sprintf(format, v...)

   l.Output(2, s)

   panic(s)

}

// Panicln is equivalent to l.Println() followed by a call to panic().

func (l *Logger) Panicln(v ...interface{}) {

   s := fmt.Sprintln(v...)

   l.Output(2, s)

   panic(s)

}

log.Panic接口函数把日志内容刷到标准错误后调用panic函数。

log.Panic接口使用示例:

package main

import (

   "log"

   "fmt"

)

func logPanicTest(){

   level := "Panic"

   defer func() {

      fmt.Println("defer Panic 1")

      if err := recover(); err != nil {

         fmt.Println(err)

      }

   }()

   log.Panic(level, " level")

   defer func() {

      fmt.Println("defer Panic 2")

   }()

}

func main() {

   logPanicTest()

}

// output

// defer Panic 1

// 2018/10/06 13:55:17 Panic level

// Panic level

第一个defer函数被调用并输出“defer Panic 1”,Panic后声明的defer不会执行。

5、logger定制

Logger是写入日志的基本组件,log模块中存在一个标准Logger,可以直接通过log进行访问,可以直接使用log.xxxx进行日志进行输出。但在实际使用中,不同类型的日志可能拥有需求,仅标准Logger不能满足日志记录的需求,通过创建不同的Logger可以将不同类型的日志分类输出。使用logger前需要首先通过New函数创建一个Logger对象,函数声明如下:

func New(out io.Writer, prefix string, flag int) *Logger {

   return &Logger{out: out, prefix: prefix, flag: flag}

}

函数接收三个参数分别是日志输出的IO对象,日志前缀和日志包含的通用信息标识位,通过对参数进行设置可以对Logger进行定制。其中IO对象通常是标准输出os.Stdout,os.Stderr,或者绑定到文件的IO。日志前缀和信息标识位可以对日志的格式进行设置。

一条日志由三个部分组成,其结构如下:

{日志前缀} {标识1} {标识2} ... {标识n} {日志内容}

日志前缀,通过prefix参数设置,可以是任意字符串。

标识,通过flags参数设置,当某个标识被设置,会在日志中进行显示,log模块中定义了如下标识,多个标识通过按位或进行组合:

Ldate 显示当前日期(当前时区)

Ltime 显示当前时间(当前时区)

Lmicroseconds 显示当前时间(微秒)

Llongfile 包含路径的完整文件名

Lshortfile 不包含路径的文件名

LUTC Ldata和Ltime使用UTC时间

LstdFlags 标准Logger的标识,等价于 Ldate | Ltime

Logger相关接口如下:

// Flags returns the output flags for the logger.

func (l *Logger) Flags() int {

   l.mu.Lock()

   defer l.mu.Unlock()

   return l.flag

}

// SetFlags sets the output flags for the logger.

func (l *Logger) SetFlags(flag int) {

   l.mu.Lock()

   defer l.mu.Unlock()

   l.flag = flag

}

// Prefix returns the output prefix for the logger.

func (l *Logger) Prefix() string {

   l.mu.Lock()

   defer l.mu.Unlock()

   return l.prefix

}

// SetPrefix sets the output prefix for the logger.

func (l *Logger) SetPrefix(prefix string) {

   l.mu.Lock()

   defer l.mu.Unlock()

   l.prefix = prefix

}

// SetOutput sets the output destination for the standard logger.

func SetOutput(w io.Writer) {

   std.mu.Lock()

   defer std.mu.Unlock()

   std.out = w

}

// Flags returns the output flags for the standard logger.

func Flags() int {

   return std.Flags()

}

// SetFlags sets the output flags for the standard logger.

func SetFlags(flag int) {

   std.SetFlags(flag)

}

// Prefix returns the output prefix for the standard logger.

func Prefix() string {

   return std.Prefix()

}

// SetPrefix sets the output prefix for the standard logger.

func SetPrefix(prefix string) {

   std.SetPrefix(prefix)

}

Logger示例如下:

package main

import (

   "log"

   "os"

)

func main() {

   prefix := "[INFO]"

   logger := log.New(os.Stdout, prefix, log.LstdFlags | log.Lshortfile)

   logger.Print("Hello Go")

   logger.SetPrefix("[OUTPUT]")

   logger.SetFlags(log.LstdFlags)

   logger.Print("Hello Logger")

}

// output

// [INFO]2018/10/06 13:24:44 main.go:11: Hello Go

// [OUTPUT]2018/10/06 13:24:44 Hello Logger

6、log分级日志实现

Go的log模块没有对日志进行分级的功能,对于日志分级需求可以在log的基础上进行实现。通过使用log模块的基础功能进行封装,可以实现Log4类似的日志功能。

package logger

import (

"fmt"

"log"

"os"

"os/exec"

"strings"

"time"

)

const (

   PanicLevel int = iota

   FatalLevel

   ErrorLevel

   WarnLevel

   InfoLevel

   DebugLevel

)

type LogFile struct {

   level    int

   logTime  int64

   fileName string

   fileFd   *os.File

}

var logFile LogFile

func Config(logFolder string, level int) {

   logFile.fileName = logFolder

   logFile.level = level

   log.SetOutput(logFile)

   log.SetFlags(log.Lmicroseconds | log.Lshortfile)

}

func SetLevel(level int) {

   logFile.level = level

}

func Debugf(format string, args ...interface{}) {

   if logFile.level >= DebugLevel {

      log.SetPrefix("debug ")

      log.Output(2, fmt.Sprintf(format, args...))

   }

}

func Infof(format string, args ...interface{}) {

   if logFile.level >= InfoLevel {

      log.SetPrefix("info ")

      log.Output(2, fmt.Sprintf(format, args...))

   }

}

func Warnf(format string, args ...interface{}) {

   if logFile.level >= WarnLevel {

      log.SetPrefix("warn ")

      log.Output(2, fmt.Sprintf(format, args...))

   }

}

func Errorf(format string, args ...interface{}) {

   if logFile.level >= ErrorLevel {

      log.SetPrefix("error ")

      log.Output(2, fmt.Sprintf(format, args...))

   }

}

func Fatalf(format string, args ...interface{}) {

   if logFile.level >= FatalLevel {

      log.SetPrefix("fatal ")

      log.Output(2, fmt.Sprintf(format, args...))

   }

}

func (me LogFile) Write(buf []byte) (n int, err error) {

   if me.fileName == "" {

      fmt.Printf("consol: %s", buf)

      return len(buf), nil

   }

   if logFile.logTime+3600 < time.Now().Unix() {

      logFile.createLogFile()

      logFile.logTime = time.Now().Unix()

   }

   if logFile.fileFd == nil {

      return len(buf), nil

   }

   return logFile.fileFd.Write(buf)

}

func (me *LogFile) createLogFile() {

   logdir := "./"

   if index := strings.LastIndex(me.fileName, "/"); index != -1 {

      logdir = me.fileName[0:index] + "/"

      os.MkdirAll(me.fileName[0:index], os.ModePerm)

   }

   now := time.Now()

   filename := fmt.Sprintf("%s_%04d%02d%02d_%02d%02d", me.fileName, now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute())

   if err := os.Rename(me.fileName, filename); err == nil {

      go func() {

         tarCmd := exec.Command("tar", "-zcf", filename+".tar.gz", filename, "--remove-files")

         tarCmd.Run()

         rmCmd := exec.Command("/bin/sh", "-c", "find "+logdir+` -type f -mtime +2 -exec rm {} \;`)

         rmCmd.Run()

      }()

   }

   for index := 0; index < 10; index++ {

      if fd, err := os.OpenFile(me.fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModeExclusive); nil == err {

         me.fileFd.Sync()

         me.fileFd.Close()

         me.fileFd = fd

         break

      }

      me.fileFd = nil

   }

}

上述logger模块封装的功能如下:

A、支持归档输出,一个小时压缩归档一份

B、最多保留三天的日志

C、支持日志级别自定义

D、如果没有指定输出文件默认输出到控制台。

E、支持输出文件名行号,以及时间、日志界别 

二、regexp

1、regexp简介

Go语言通过regexp标准包为正则表达式提供了官方支持。在Go语言环境中可以使用下列命令查看正则表达式的语法:

go doc regexp/syntax

2、Regexp正则对象

Regexp是一个编译好的正则表达式对象。

type Regexp struct {

   // read-only after Compile

   regexpRO

   // cache of machines for running regexp

   mu      sync.Mutex

   machine []*machine

}

通常需要使用正则表达式构建一个正则对象

3、regexp常用接口

func Match(pattern string, b []byte) (matched bool, err error)

func MatchString(pattern string, s string) (matched bool, err error)

func MatchReader(pattern string, r io.RuneReader) (matched bool, err error)

判断在b中能否找到pattern所匹配的字符串

func Compile(expr string) (*Regexp, error)

将正则表达式编译成一个正则对象(使用PERL语法)。

该正则对象会采用“leftmost-first”模式。选择第一个匹配结果。

如果正则表达式语法错误,则返回错误信息。

func CompilePOSIX(expr string) (*Regexp, error)

将正则表达式编译成一个正则对象(正则语法限制在 POSIX ERE 范围内)。

该正则对象会采用“leftmost-longest”模式。选择最长的匹配结果。

POSIX 语法不支持Perl的语法格式:\d、\D、\s、\S、\w、\W

如果正则表达式语法错误,则返回错误信息。

func MustCompile(str string) *Regexp

func MustCompilePOSIX(str string) *Regexp

将正则表达式编译成一个正则对象,但会在解析失败时panic

func (re *Regexp) Longest()

让正则表达式在之后的搜索中都采用“leftmost-longest”模式。

func (re *Regexp) String() string

返回编译时使用的正则表达式字符串

func (re *Regexp) NumSubexp() int

返回正则表达式中分组的数量

func (re *Regexp) SubexpNames() []string

返回正则表达式中分组的名字

第 0 个元素表示整个正则表达式的名字,永远是空字符串。

func (re *Regexp) LiteralPrefix() (prefix string, complete bool)

返回正则表达式必须匹配到的字面前缀(不包含可变部分)。

如果整个正则表达式都是字面值,则 complete 返回 true。

4、regexp示例

package main

import (

   "regexp"

   "fmt"

)

var mailRegexp = regexp.MustCompile(`([A-Za-z0-9]+)@([A-Za-z0-9.]+)\.([A-Za-z0-9.]+)`)

func main() {

   s := " hello's email is hellogo@gmail.com"

   matches := mailRegexp.FindStringSubmatch(s)

   fmt.Println(matches)// [hellogo@gmail.com hellogo gmail com]

   fmt.Println(matches[0]) // hellogo@gmail.com

   fmt.Println(matches[1]) // hellogo

   fmt.Println(matches[2]) // gmail

   fmt.Println(matches[3]) // com

}

三、strconv

1、strconv简介

strconv提供了字符串与基本类型的转换函数接口。

2、字符串与bool类型转换

func ParseBool(str string) (value bool, err error)

ParseBool将字符串转换为布尔值。接受真值:1, t, T, TRUE, true, True;接受假值:0, f, F, FALSE, false, False;其它任何值都返回一个错误。

package main

import (

   "fmt"

   "strconv"

)

func main() {

   fmt.Println(strconv.ParseBool("1"))    // true

   fmt.Println(strconv.ParseBool("t"))    // true

   fmt.Println(strconv.ParseBool("T"))    // true

   fmt.Println(strconv.ParseBool("true")) // true

   fmt.Println(strconv.ParseBool("True")) // true

   fmt.Println(strconv.ParseBool("TRUE")) // true

   fmt.Println(strconv.ParseBool("TRue"))

   // false strconv.ParseBool: parsing "TRue": invalid syntax

   fmt.Println(strconv.ParseBool("0"))     // false

   fmt.Println(strconv.ParseBool("f"))     // false

   fmt.Println(strconv.ParseBool("F"))     // false

   fmt.Println(strconv.ParseBool("false")) // false

   fmt.Println(strconv.ParseBool("False")) // false

   fmt.Println(strconv.ParseBool("FALSE")) // false

   fmt.Println(strconv.ParseBool("FALse"))

   // false strconv.ParseBool: parsing "FAlse": invalid syntax

}

func FormatBool(b bool) string

FormatBool将布尔值转换为字符串"true"或"false"

package main

import (

   "fmt"

   "strconv"

)

func main() {

   fmt.Println(strconv.FormatBool(0 < 1)) // true

   fmt.Println(strconv.FormatBool(0 > 1)) // false

}

func AppendBool(dst []byte, b bool) []byte

AppendBool将布尔值b转换为字符串"true"或"false",然后将结果追加到dst的尾部,返回追加后的[]byte。

package main

import (

   "fmt"

   "strconv"

)

func main() {

   rst := make([]byte, 0)

   rst = strconv.AppendBool(rst, 0 < 1)

   fmt.Printf("%s\n", rst) // true

   rst = strconv.AppendBool(rst, 0 > 1)

   fmt.Printf("%s\n", rst) // truefalse

}

3、字符串与整型转换

func ParseInt(s string, base int, bitSize int) (i int64, err error)

ParseInt将字符串转换为int类型

s:要转换的字符串

base:进位制(2进制到36进制)

bitSize:指定整数类型(0:int、8:int8、16:int16、32:int32、64:int64)

返回转换后的结果和转换时遇到的错误,如果base为0,则根据字符串的前缀判断进位制(0x:16,0:8,其它:10)。

package main

import (

   "fmt"

   "strconv"

)

func main() {

   fmt.Println(strconv.ParseInt("123", 10, 8))

   // 123

   fmt.Println(strconv.ParseInt("12345", 10, 8))

   // 127 strconv.ParseInt: parsing "12345": value out of range

   fmt.Println(strconv.ParseInt("2147483647", 10, 0))

   // 2147483647

   fmt.Println(strconv.ParseInt("0xFF", 16, 0))

   // 0 strconv.ParseInt: parsing "0xFF": invalid syntax

   fmt.Println(strconv.ParseInt("FF", 16, 0))

   // 255

   fmt.Println(strconv.ParseInt("0xFF", 0, 0))

   // 255

}

func ParseUint(s string, base int, bitSize int) (n uint64, err error)

ParseUint将字符串转换为uint类型

package main

import (

   "fmt"

   "strconv"

)

func main() {

   fmt.Println(strconv.ParseUint("FF", 16, 8))

   // 255

}

func Atoi(s string) (i int, err error)

Atoi相当于ParseInt(s, 10, 0)

func FormatInt(i int64, base int) string

FormatUint将int型整数i转换为字符串形式

base:进位制(2进制到36进制),大于10进制的数,返回值使用小写字母'a'到'z'

package main

import (

   "fmt"

   "strconv"

)

func main() {

   i := int64(-2048)

   fmt.Println(strconv.FormatInt(i, 2))  // -100000000000

   fmt.Println(strconv.FormatInt(i, 8))  // -4000

   fmt.Println(strconv.FormatInt(i, 10)) // -2048

   fmt.Println(strconv.FormatInt(i, 16)) // -800

   fmt.Println(strconv.FormatInt(i, 36)) // -1kw

}

func Itoa(i int) string

Itoa相当于FormatInt(i, 10)

func AppendInt(dst []byte, i int64, base int) []byte

AppendInt将int型整数i转换为字符串形式,并追加到dst的尾部

i:要转换的字符串,base:进位制,返回追加后的[]byte。

func AppendUint(dst []byte, i uint64, base int) []byte

AppendUint将uint型整数i转换为字符串形式,并追加到dst的尾部

i:要转换的字符串,base:进位制,返回追加后的[]byte。

4、字符串与浮点型转换

func ParseFloat(s string, bitSize int) (f float64, err error)

ParseFloat将字符串转换为浮点数,

s:要转换的字符串

bitSize:指定浮点类型(32:float32、64:float64)

如果s是合法的格式,而且接近一个浮点值,则返回浮点数的四舍五入值(依据 IEEE754 的四舍五入标准);如果s不是合法的格式,则返回“语法错误”;如果转换结果超出bitSize范围,则返回“超出范围”。

package main

import (

   "fmt"

   "strconv"

)

func main() {

   s := "0.12345678901234567890"

   f, err := strconv.ParseFloat(s, 32)

   fmt.Println(f, err)          // 0.12345679104328156

   fmt.Println(float32(f), err) // 0.12345679

   f, err = strconv.ParseFloat(s, 64)

   fmt.Println(f, err) // 0.12345678901234568

}

func FormatFloat(f float64, fmt byte, prec, bitSize int) string

FormatFloat 将浮点数 f 转换为字符串值

f:要转换的浮点数

fmt:格式标记(b、e、E、f、g、G)

prec:精度(数字部分的长度,不包括指数部分)

bitSize:指定浮点类型(32:float32、64:float64)

格式标记:

'b' (-ddddp±ddd,二进制指数)

'e' (-d.dddde±dd,十进制指数)

'E' (-d.ddddE±dd,十进制指数)

'f' (-ddd.dddd,没有指数)

'g' ('e':大指数,'f':其它情况)

'G' ('E':大指数,'f':其它情况)

如果格式标记为 'e','E'和'f',则prec表示小数点后的数字位数

如果格式标记为 'g','G',则prec表示总的数字位数(整数部分+小数部分)

package main

import (

   "fmt"

   "strconv"

)

func main() {

   f := 100.12345678901234567890123456789

   fmt.Println(strconv.FormatFloat(f, 'b', 5, 32))

   // 13123382p-17

   fmt.Println(strconv.FormatFloat(f, 'e', 5, 32))

   // 1.00123e+02

   fmt.Println(strconv.FormatFloat(f, 'E', 5, 32))

   // 1.00123E+02

   fmt.Println(strconv.FormatFloat(f, 'f', 5, 32))

   // 100.12346

   fmt.Println(strconv.FormatFloat(f, 'g', 5, 32))

   // 100.12

   fmt.Println(strconv.FormatFloat(f, 'G', 5, 32))

   // 100.12

   fmt.Println(strconv.FormatFloat(f, 'b', 30, 32))

   // 13123382p-17

   fmt.Println(strconv.FormatFloat(f, 'e', 30, 32))

   // 1.001234588623046875000000000000e+02

   fmt.Println(strconv.FormatFloat(f, 'E', 30, 32))

   // 1.001234588623046875000000000000E+02

   fmt.Println(strconv.FormatFloat(f, 'f', 30, 32))

   // 100.123458862304687500000000000000

   fmt.Println(strconv.FormatFloat(f, 'g', 30, 32))

   // 100.1234588623046875

   fmt.Println(strconv.FormatFloat(f, 'G', 30, 32))

   // 100.1234588623046875

}

func AppendFloat(dst []byte, f float64, fmt byte, prec int, bitSize int) []byte

AppendFloat将浮点数f转换为字符串值,并将转换结果追加到dst的尾部,返回追加后的[]byte

package main

import (

   "fmt"

   "strconv"

)

func main() {

   f := 100.12345678901234567890123456789

   b := make([]byte, 0)

   b = strconv.AppendFloat(b, f, 'f', 5, 32)

   b = append(b, " "...)

   b = strconv.AppendFloat(b, f, 'e', 5, 32)

   fmt.Printf("%s", b) // 100.12346 1.00123e+0

}

5、特殊字符处理函数

func Quote(s string) string

Quote将字符串s转换为“双引号”引起来的字符串

其中的特殊字符将被转换为“转义字符”,“不可显示的字符”将被转换为“转义字符”。

package main

import (

   "fmt"

   "strconv"

)

func main() {

   fmt.Println(strconv.Quote(`/home/user`)) // "/home/user"

}

func AppendQuote(dst []byte, s string) []byte

AppendQuote将字符串s转换为“双引号”引起来的字符串,并将结果追加到dst的尾部,返回追加后的[]byte。其中的特殊字符将被转换为“转义字符”。

func QuoteToASCII(s string) string

QuoteToASCII将字符串s转换为“双引号”引起来的ASCII字符串,“非ASCII字符”和“特殊字符”将被转换为“转义字符”。

func AppendQuoteToASCII(dst []byte, s string) []byte

AppendQuoteToASCII将字符串s转换为“双引号”引起来的 ASCII 字符串,并将结果追加到dst的尾部,返回追加后的[]byte,“非 ASCII 字符”和“特殊字符”将被转换为“转义字符”。

func QuoteRune(r rune) string

QuoteRune将Unicode字符转换为“单引号”引起来的字符串,“特殊字符”将被转换为“转义字符”。

func AppendQuoteRune(dst []byte, r rune) []byte

AppendQuoteRune将Unicode字符转换为“单引号”引起来的字符串,并将结果追加到dst的尾部,返回追加后的[]byte。“特殊字符”将被转换为“转义字符”。

func QuoteRuneToASCII(r rune) string

QuoteRuneToASCII将Unicode字符转换为“单引号”引起来的ASCII字符串,“非 ASCII字符”和“特殊字符”将被转换为“转义字符”。

func AppendQuoteRuneToASCII(dst []byte, r rune) []byte

AppendQuoteRune将Unicode字符转换为“单引号”引起来的ASCII字符串,并将结果追加到dst的尾部,返回追加后的[]byte,“非 ASCII 字符”和“特殊字符”将被转换为“转义字符”。

func CanBackquote(s string) bool

CanBackquote判断字符串s是否可以表示为一个单行的“反引号”字符串,字符串中不能含有控制字符(除了\t)和“反引号”字符,否则返回false。

func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error)

UnquoteChar 将 s 中的第一个字符“取消转义”并解码

s:转义后的字符串

quote:字符串使用的“引号符”(用于对引号符“取消转义”)

value: 解码后的字符

multibyte:value是否为多字节字符

tail: 字符串s除去value后的剩余部分

error:返回s中是否存在语法错误

参数 quote 为“引号符”

如果设置为单引号,则 s 中允许出现 \' 字符,不允许出现单独的 ' 字符

如果设置为双引号,则 s 中允许出现 \" 字符,不允许出现单独的 " 字符

如果设置为 0,则不允许出现 \' 或 \" 字符,可以出现单独的 ' 或 " 字符

func Unquote(s string) (t string, err error)

Unquote 将“带引号的字符串” s 转换为常规的字符串(不带引号和转义字符)

s可以是“单引号”、“双引号”或“反引号”引起来的字符串(包括引号本身)

如果s是单引号引起来的字符串,则返回该该字符串代表的字符

func IsPrint(r rune) bool

IsPrint判断Unicode字符r是否是一个可显示的字符,空格可以显示,而\t则不能显示。

四、time

1、time简介

time包提供显示和计算时间用的函数。Go中时间处理依赖的数据类型: time.Time, time.Month, time.Weekday, time.Duration, time.Location。

2、time.Time时间点

time.Time 代表一个纳秒精度的时间点,定义如下:

type Time struct {

   sec int64 // 从1年1月1日 00:00:00 UTC 至今过去的秒数

   nsec int32 // 最近一秒到下一秒过去的纳秒数

   loc *Location // 时区

}

time.Time使用示例:

package main

import (

   "fmt"

   "time"

)

func main() {

   var t time.Time // 定义 time.Time 类型变量

   t = time.Now()  // 获取当前时间

   fmt.Printf("时间: %v, 时区:  %v,  时间类型: %T\n", t, t.Location(), t)

   // time.UTC() time 返回UTC 时区的时间

   fmt.Printf("时间: %v, 时区:  %v,  时间类型: %T\n", t.UTC(), t.UTC().Location(), t)

}

// output

// 时间: 2018-10-06 15:31:06.730640277 +0800 CST m=+0.000273307, 时区:  Local,  时间类型: time.Time

// 时间: 2018-10-06 07:31:06.730640277 +0000 UTC, 时区:  UTC,  时间类型: time.Time

时间获取的接口:

func Now() Time {} // 当前本地时间

func Unix(sec int64, nsec int64) Time {} // 根据时间戳返回本地时间

func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time {} // 返回指定时间

时间显示的接口:

func (t Time) UTC() Time {} // 获取指定时间在UTC 时区的时间表示

func (t Time) Local() Time {} // 以本地时区表示

func (t Time) In(loc *Location) Time {} // 时间在指定时区的表示

func (t Time) Format(layout string) string {} // 按指定格式显示时间

日期信息获取的接口:

func (t Time) Date() (year int, month Month, day int) {} // 返回时间的日期信息

func (t Time) Year() int {} // 返回年

func (t Time) Month() Month {} // 月

func (t Time) Day() int {} // 日

func (t Time) Weekday() Weekday {} // 星期

func (t Time) ISOWeek() (year, week int) {} // 返回年,星期范围编号

func (t Time) Clock() (hour, min, sec int) {} // 返回时间的时分秒

func (t Time) Hour() int {} // 返回小时

func (t Time) Minute() int {} // 分钟

func (t Time) Second() int {} // 秒

func (t Time) Nanosecond() int {} // 纳秒

func (t Time) YearDay() int {} // 一年中对应的天

func (t Time) Location() *Location {} // 时间的时区

func (t Time) Zone() (name string, offset int) {} // 时间所在时区的规范名和想对UTC 时间偏移量

func (t Time) Unix() int64 {} // 时间转为时间戳

func (t Time) UnixNano() int64 {} // 时间转为时间戳(纳秒)

时间比较与计算的接口:

func (t Time) IsZero() bool {} // 是否是零时时间

func (t Time) After(u Time) bool {} // 时间在u 之前

func (t Time) Before(u Time) bool {} // 时间在u 之后

func (t Time) Equal(u Time) bool {} // 时间与u 相同

func (t Time) Add(d Duration) Time {} // 返回t +d 的时间点

func (t Time) Sub(u Time) Duration {} // 返回 t-u

func (t Time) AddDate(years int, months int, days int) Time {} //返回增加了给出的年份、月份和天数的时间点Time

时间序列化的接口:

func (t Time) MarshalBinary() ([]byte, error) {} // 时间序列化

func (t Time) UnmarshalBinary(data []byte) error {} // 反序列化

func (t Time) MarshalJSON() ([]byte, error) {} // 时间序列化

func (t Time) MarshalText() ([]byte, error) {} // 时间序列化

func (t Time) GobEncode() ([]byte, error) {} // 时间序列化

func (t Time) GobDecode() ([]byte, error) {} // 时间序列化

3、 time.Month月份

time.Month 代表一年中的某个月

type Month int

const (

   January Month = 1 + iota

   February

   March

   April

   May

   June

   July

   August

   September

   October

   November

   December

)

4、time.Weekday星期

time.Weekday 代表一周的周几

type Weekday int

const (

   Sunday Weekday = iota

   Monday

   Tuesday

   Wednesday

   Thursday

   Friday

   Saturday

)

5、time.Duration时间段

time.Duration 类型代表两个时间点之间经过的纳秒数,可表示的最长时间段约为290年。

type Duration int64

const (

   Nanosecond  Duration = 1

   Microsecond          = 1000 * Nanosecond

   Millisecond          = 1000 * Microsecond

   Second               = 1000 * Millisecond

   Minute               = 60 * Second

   Hour                 = 60 * Minute

)

输出和改变时间段单位的接口:

func (d Duration) String() string // 格式化输出 Duration

func (d Duration) Nanoseconds() int64 // 将时间段表示为纳秒

func (d Duration) Seconds() float64 // 将时间段表示为秒

func (d Duration) Minutes() float64 // 将时间段表示为分钟

func (d Duration) Hours() float64 // 将时间段表示为小时

6、time.Locations时区

Location代表一个地点,以及该地点所在的时区信息。北京时间可以使用 Asia/Shanghai。

type Location struct {

   name string

   zone []zone

   tx   []zoneTrans

   cacheStart int64

   cacheEnd   int64

   cacheZone  *zone

}

var UTC *Location = &utcLoc

var Local *Location = &localLoc

时区导出的接口:

func (l *Location) String() string // 输出时区名

func FixedZone(name string, offset int) *Location // FixedZone 使用给定的地点名name和时间偏移量offset(单位秒)创建并返回一个Location

func LoadLocation(name string) (*Location, error) // LoadLocation 使用给定的名字创建Location

7、其它接口

func Sleep(d Duration) 

阻塞当前go协程至少d代表的时间段。d<=0时,Sleep会立刻返回。

五、errors

1、errors简介

Go语言使用error类型来返回函数执行过程中遇到的错误,如果返回error值为nil,则表示未遇到错误,否则error会返回一个字符串。error是一个预定义标识符,代表一个Go语言內建的接口类型,任何自定义的错误类型都要实现Error接口函数。

type error interface {

   Error() string

}

2、error常用接口

func New(text string) error

将字符串text包装成一个error对象返回 

import (

   "errors"

   "fmt"

)

var ErrUnexpectedEOF = errors.New("unexpected EOF")

func main() {

   fmt.Println(ErrUnexpectedEOF)

}

3、error定制

Go语言工程开发中,通常需要根据使用场景定制不同的error类型,此时需要实现Error接口。

package errors_test

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 Example() {

   if err := oops(); err != nil {

      fmt.Println(err)

   }

   // Output: 1989-03-15 22:30:00 +0000 UTC: the file system has gone away

}

©著作权归作者所有:来自51CTO博客作者天山老妖S的原创作品,如需转载,请注明出处,否则将追究法律责任


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消