Go 语言常用包笔记
bufio 包实现了带缓存的 I/O 操作。
Read 相关函数 NewReaderSize、NewReader 1 func NewReaderSize (rd io.Reader, size int ) *Reader
NewReaderSize 将 rd 封装成一个带缓存的 bufio.Reader 对象,缓存大小由 size 指定(如果小于 16 则会被设置为 16)。
如果 rd 的基类型就是有足够缓存的 bufio.Reader 类型,则直接将 rd 转换为基类型返回。
1 func NewReader (rd io.Reader) *Reader
NewReader 相当于 NewReaderSize(rd, 4096)。
bufio.Reader 实现了如下接口:
1 2 3 4 io.Reader io.WriterTo io.ByteScanner io.RuneScanner
Peek 1 func (b *Reader) Peek (n int ) ([]byte , error)
Peek 返回缓存的一个切片,该切片引用缓存中前 n 个字节的数据,该操作不会将数据读出,只是引用,引用的数据在下一次读取操作之前是有效的。如果切片长度小于 n,则返回一个错误信息说明原因。如果 n 大于缓存的总大小,则返回 ErrBufferFull。
Read 1 func (b *Reader) Read (p []byte ) (n int , err error)
Read 从 b 中读出数据到 p 中,返回读出的字节数和遇到的错误。
如果缓存不为空,则只能读出缓存中的数据,不会从底层 io.Reader中提取数据,如果缓存为空,则:
1、len(p) >= 缓存大小,则跳过缓存,直接从底层 io.Reader 中读出到 p 中。
2、len(p) < 缓存大小,则先将数据从底层 io.Reader 中读取到缓存中,再从缓存读取到 p 中。
Buffered 1 func (b *Reader) Buffered () int
Buffered 返回缓存中未读取的数据的长度。
Discard 1 func (b *Reader) Discard (n int ) (discarded int , err error)
Discard 跳过后续的 n 个字节的数据,返回跳过的字节数。
如果结果小于 n,将返回错误信息。
如果 n 小于缓存中的数据长度,则不会从底层提取数据。
ReadSlice 1 func (b *Reader) ReadSlice (delim byte ) (line []byte , err error)
ReadSlice 在 b 中查找 delim 并返回 delim 及其之前的所有数据。
该操作会读出数据,返回的切片是已读出的数据的引用,切片中的数据在下一次读取操作之前是有效的。
如果找到 delim,则返回查找结果,err 返回 nil。
如果未找到 delim,则:
1、缓存不满,则将缓存填满后再次查找。
2、缓存是满的,则返回整个缓存,err 返回 ErrBufferFull。
如果未找到 delim 且遇到错误(通常是 io.EOF),则返回缓存中的所有数据和遇到的错误。 因为返回的数据有可能被下一次的读写操作修改,所以大多数操作应该使用 ReadBytes 或 ReadString,它们返回的是数据的拷贝 。
ReadLine 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 func (b *Reader) ReadLine () (line []byte , isPrefix bool , err error)
ReadBytes、ReadString 1 func (b *Reader) ReadBytes (delim byte ) (line []byte , err error)
ReadBytes 功能同 ReadSlice,只不过返回的是缓存的拷贝。
1 func (b *Reader) ReadString (delim byte ) (line string , err error)
ReadString 功能同 ReadBytes,只不过返回的是字符串。
Reset 1 func (b *Reader) Reset (r io.Reader)
Reset 将 b 的底层 Reader 重新指定为 r,同时丢弃缓存中的所有数据,复位 所有标记和错误信息。 bufio.Reader。
示例1:Peek、Read、Discard、Buffered 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 func main () { sr := strings.NewReader("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" ) buf := bufio.NewReaderSize(sr, 0 ) b := make ([]byte , 10 ) fmt.Println(buf.Buffered()) s, _ := buf.Peek(5 ) s[0 ], s[1 ], s[2 ] = 'a' , 'b' , 'c' fmt.Printf("%d %q\n" , buf.Buffered(), s) buf.Discard(1 ) for n, err := 0 , error(nil ); err == nil ; { n, err = buf.Read(b) fmt.Printf("%d %q %v\n" , buf.Buffered(), b[:n], err) } }
示例2:ReadLine 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 func main () { sr := strings.NewReader("ABCDEFGHIJKLMNOPQRSTUVWXYZ\n1234567890" ) buf := bufio.NewReaderSize(sr, 0 ) for line, isPrefix, err := []byte {0 }, false , error(nil ); len (line) > 0 && err == nil ; { line, isPrefix, err = buf.ReadLine() fmt.Printf("%q %t %v\n" , line, isPrefix, err) } fmt.Println("----------" ) buf = bufio.NewReaderSize(strings.NewReader("ABCDEFG\n" ), 0 ) for line, isPrefix, err := []byte {0 }, false , error(nil ); len (line) > 0 && err == nil ; { line, isPrefix, err = buf.ReadLine() fmt.Printf("%q %t %v\n" , line, isPrefix, err) } fmt.Println("----------" ) buf = bufio.NewReaderSize(strings.NewReader("ABCDEFG" ), 0 ) for line, isPrefix, err := []byte {0 }, false , error(nil ); len (line) > 0 && err == nil ; { line, isPrefix, err = buf.ReadLine() fmt.Printf("%q %t %v\n" , line, isPrefix, err) } }
示例3:ReadSlice 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 func main () { buf := bufio.NewReaderSize(strings.NewReader("ABCDEFG\n" ), 0 ) for line, err := []byte {0 }, error(nil ); len (line) > 0 && err == nil ; { line, err = buf.ReadSlice('\n' ) fmt.Printf("%q %v\n" , line, err) } fmt.Println("----------" ) buf = bufio.NewReaderSize(strings.NewReader("ABCDEFG" ), 0 ) for line, err := []byte {0 }, error(nil ); len (line) > 0 && err == nil ; { line, err = buf.ReadSlice('\n' ) fmt.Printf("%q %v\n" , line, err) } }
Write 相关函数 NewWriterSize、NewWriter 1 2 3 4 5 func NewWriterSize (wr io.Writer, size int ) *Writer
1 2 func NewWriter (wr io.Writer) *Writer
bufio.Writer 实现了如下接口:
1 2 3 io .Writer io .ReaderFrom io .ByteWriter
WriteString 1 func (b *Writer) WriteString (s string ) (int , error)
WriteString 功能同 Write,只不过写入的是字符串。
WriteRune 1 func (b *Writer) WriteRune (r rune ) (size int , err error)
WriteRune 向 b 写入 r 的 UTF-8 编码,返回 r 的编码长度。
Flush 1 func (b *Writer) Flush () error
Flush 将缓存中的数据提交到底层的 io.Writer 中。
Available 1 func (b *Writer) Available () int
Available 返回缓存中未使用的空间的长度。
Buffered 1 func (b *Writer) Buffered () int
Buffered 返回缓存中未提交的数据的长度。
Reset 1 func (b *Writer) Reset (w io.Writer)
Reset 将 b 的底层 Writer 重新指定为 w,同时丢弃缓存中的所有数据,复位所有标记和错误信息。相当于创建了一个新的 bufio.Writer。
示例1:Available、Buffered、WriteString、Flush 1 2 3 4 5 6 7 8 9 10 func main () { buf := bufio.NewWriterSize(os.Stdout, 0 ) fmt.Println(buf.Available(), buf.Buffered()) buf.WriteString("ABCDEFGHIJKLMNOPQRSTUVWXYZ" ) fmt.Println(buf.Available(), buf.Buffered()) buf.Flush() }
type ReadWriter ReadWriter 集成了 bufio.Reader 和 bufio.Writer。
1 2 3 4 type ReadWriter struct { *Reader *Writer }
1 func NewReadWriter (r *Reader, w *Writer) *ReadWriter
NewReadWriter 将 r 和 w 封装成一个 bufio.ReadWriter 对象。
type Scanner 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 type Scanner struct { ... }
1 func NewScanner (r io.Reader) *Scanner
NewScanner 创建一个 Scanner 来扫描 r,默认匹配函数为 ScanLines。
1 func (s *Scanner) Buffer (buf []byte , max int )
Buffer 用于设置自定义缓存及其可扩展范围,如果 max 小于 len(buf),则 buf 的尺寸将固定不可调。Buffer 必须在第一次 Scan 之前设置,否则会引发 panic。
默认情况下,Scanner 会使用一个 4096 - bufio.MaxScanTokenSize 大小的内部缓存。
1 func (s *Scanner) Split (split SplitFunc)
Split 用于设置“匹配函数”,这个函数必须在调用 Scan 前执行。
type SplitFunc 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 type SplitFunc func (data []byte , atEOF bool ) (advance int , token []byte , err error)
1 func (s *Scanner) Scan () bool
Scan 开始一次扫描过程,如果匹配成功,可以通过 Bytes() 或 Text() 方法取出结果,如果遇到错误,则终止扫描,并返回 false。
1 func (s *Scanner) Bytes () []byte
Bytes 将最后一次扫描出的“匹配部分”作为一个切片引用返回,下一次的 Scan 操作会覆盖本次引用的内容。
1 func (s *Scanner) Text () string
Text 将最后一次扫描出的“匹配部分”作为字符串返回(返回副本)。
1 func (s *Scanner) Err () error
Err 返回扫描过程中遇到的非 EOF 错误,供用户调用,以便获取错误信息。
1 func ScanBytes (data []byte , atEOF bool ) (advance int , token []byte , err error)
ScanBytes 是一个“匹配函数”用来找出 data 中的单个字节并返回。
1 func ScanRunes (data []byte , atEOF bool ) (advance int , token []byte , err error)
ScanRunes 是一个“匹配函数”,用来找出 data 中单个 UTF8 字符的编码。如果 UTF8 编码错误,则 token 会返回 “\xef\xbf\xbd”(即:U+FFFD),但只消耗 data 中的一个字节。
这使得调用者无法区分“真正的U+FFFD字符”和“解码错误的返回值”。
1 func ScanLines (data []byte , atEOF bool ) (advance int , token []byte , err error)
ScanLines 是一个“匹配函数”,用来找出 data 中的单行数据并返回(包括空行)。
行尾标记可以是 \n 或 \r\n(返回值不包含行尾标记)
1 func ScanWords (data []byte , atEOF bool ) (advance int , token []byte , err error)
ScanWords 是一个“匹配函数”,用来找出 data 中以空白字符分隔的单词。
空白字符由 unicode.IsSpace 定义。
示例1:扫描 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 func main () { const input = "1,2,3,4," scanner := bufio.NewScanner(strings.NewReader(input)) onComma := func (data []byte , atEOF bool ) (advance int , token []byte , err error) { for i := 0 ; i < len (data); i++ { if data[i] == ',' { return i + 1 , data[:i], nil } } if atEOF { return 0 , data, bufio.ErrFinalToken } else { return 0 , nil , nil } } scanner.Split(onComma) for scanner.Scan() { fmt.Printf("%q " , scanner.Text()) } if err := scanner.Err(); err != nil { fmt.Fprintln(os.Stderr, "reading input:" , err) } }
示例2:待检查扫描 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 func main () { const input = "1234 5678 1234567901234567890 90" scanner := bufio.NewScanner(strings.NewReader(input)) split := func (data []byte , atEOF bool ) (advance int , token []byte , err error) { advance, token, err = bufio.ScanWords(data, atEOF) if err == nil && token != nil { _, err = strconv.ParseInt(string (token), 10 , 32 ) } return } scanner.Split(split) for scanner.Scan() { fmt.Printf("%s\n" , scanner.Text()) } if err := scanner.Err(); err != nil { fmt.Printf("Invalid input: %s" , err) } }
bytes 包对于传入 []byte 的函数,都不会修改传入的参数,返回值要么是参数的副本,要么是参数的切片。
转换 将s中所有字符修改为大写(小写、标题)格式返回 1 2 3 func ToUpper (s []byte ) []byte func ToLower (s []byte ) []byte func ToTitle (s []byte ) []byte
使用指定的映射表将 s 中的所有字符修改为大写(小写、标题)格式返回 1 2 3 func ToUpperSpecial (_case unicode.SpecialCase, s []byte ) []byte func ToLowerSpecial (_case unicode.SpecialCase, s []byte ) []byte func ToTitleSpecial (_case unicode.SpecialCase, s []byte ) []byte
将 s 中的所有单词的首字符修改为 Title 格式返回 1 func Title (s []byte ) []byte
BUG: 不能很好的处理以 Unicode 标点符号分隔的单词
比较 比较两个[]byte的字典顺序 nil 参数相当于空[]byte
1 func Compare (a, b []byte ) int
a < b 返回 -1 a == b 返回 0 a > b 返回 1
判断a、b是否相等 nil 相当于空[]byte
1 func Equal (a, b []byte ) bool
判断s,t是否相似 忽略大写、小写、标题三种格式的区别。 参考 unicode.SimpleFold 函数
1 func EqualFold (s, t []byte ) bool
清理 去掉 s 左右两边包含在cutset中的字符(返回s的切片) 1 2 3 func Trim (s []byte , cutset string ) []byte func TrimLeft (s []byte , cutset string ) []byte func TrimRight (s []byte , cutset string ) []byte
去掉s两边符合f要求的字符(返回s的切片) 1 2 3 func TrimFunc (s []byte , f func (r rune ) bool ) []byte func TrimLeftFunc (s []byte , f func (r rune ) bool ) []byte func TrimRightFunc (s []byte , f func (r rune ) bool ) []byte
去掉s两边的空白(unicode.IsSpace)(返回s的切片) 1 func TrimSpace (s []byte ) []byte
去掉 s 的前缀 prefix(后缀 suffix)(返回 s 的切片) 1 2 func TrimPrefix (s, prefix []byte ) []byte func TrimSuffix (s, suffix []byte ) []byte
拆合 Split按seq分割 Split 以 sep 为分隔符将 s 切分成多个子串,结果不包含分隔符。 如果 sep 为空,则将 s 切分成 Unicode 字符列表。 SplitN 可以指定切分次数 n,超出 n 的部分将不进行切分。
1 2 func Split (s, sep []byte ) [][]byte func SplitN (s, sep []byte , n int ) [][]byte
SplitAfter 功能同 Split,只不过结果包含分隔符(在各个子串尾部)。
1 2 func SplitAfter (s, sep []byte ) [][]byte func SplitAfterN (s, sep []byte , n int ) [][]byte
Fields 空白符分割 以连续空白为分隔符将 s 切分成多个子串,结果不包含分隔符。
1 func Fields (s []byte ) [][]byte
以符合 f 的字符为分隔符将 s 切分成多个子串,结果不包含分隔符 1 func FieldsFunc (s []byte , f func (rune ) bool ) [][]byte
Join,sep为连接符 1 func Join (s [][]byte , sep []byte ) []byte
把子串b重复count次吼返回 1 func Repeat (b []byte , count int ) []byte
eg.
1 2 3 4 5 6 7 8 9 10 11 12 func main () { b := []byte (" Hello World ! " ) fmt.Printf("%q\n" , bytes.Split(b, []byte {' ' })) fmt.Printf("%q\n" , bytes.Fields(b)) f := func (r rune ) bool { return bytes.ContainsRune([]byte (" !" ), r) } fmt.Printf("%q\n" , bytes.FieldsFunc(b, f)) }
子串 判断前缀、后缀 1 2 func HasPrefix (s, prefix []byte ) bool func HasSuffix (s, suffix []byte ) bool
是否包含子串subslice 或字符r 1 2 func Contains (b, subslice []byte ) bool func ContainsRune (b []byte , r rune ) bool
是否包含chars中任一字符 1 func ContainsAny (b []byte , chars string ) bool
查找子串seq(字节c、字符r)在s中第一次出现的位置 找不到则返回-1
1 2 3 func Index (s, sep []byte ) int func IndexByte (s []byte , c byte ) int func IndexRune (s []byte , r rune ) int
查找chars中任一字符在s中第一次出现的位置 找不到则返回-1
1 func IndexAny (s []byte , chars string ) int
查找符合f的字符在s中第一次出现的位置 找不到则返回-1
1 func IndexFunc (s []byte , f func (r rune ) bool ) int
功能同上,只不过查找最后一次出现的位置 1 2 3 4 func LastIndex (s, sep []byte ) int func LastIndexByte (s []byte , c byte ) int func LastIndexAny (s []byte , chars string ) int func LastIndexFunc (s []byte , f func (r rune ) bool ) int
获取seq在s中出现的次数(不重叠) 1 func Count (s, sep []byte ) int
替换 s中前n个old替换为new,n<0则替换全部 1 func Replace (s, old, new []byte , n int ) []byte
将 s 中的字符替换为 mapping(r) 的返回值 如果 mapping 返回负值,则丢弃该字符
1 func Map (mapping func (r rune ) rune , s []byte ) []byte
将s转换为[]rune类型返回 1 func Runes (s []byte ) []rune
type type Reader 1 type Reader struct { ... }
将 b 包装成 bytes.Reader 对象。
1 func NewReader (b []byte ) *Reader
bytes.Reader 实现了如下接口:
1 2 3 4 5 io .ReadSeeker io .ReaderAt io .WriterTo io .ByteScanner io .RuneScanner
返回未读取部分的数据长度:
1 func (r *Reader) Len () int
返回底层数据的总长度,方便ReadAt使用,返回值永远不变:
1 func (r *Reader) Size () int64
将底层数据切换为 b,同时复位所有标记(读取位置等信息)
1 func (r *Reader) Reset (b []byte )
eg.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 func main () { b1 := []byte ("Hello World!" ) b2 := []byte ("Hello 世界!" ) buf := make ([]byte , 6 ) rd := bytes.NewReader(b1) rd.Read(buf) fmt.Printf("%q\n" , buf) rd.Read(buf) fmt.Printf("%q\n" , buf) rd.Reset(b2) rd.Read(buf) fmt.Printf("%q\n" , buf) fmt.Printf("Size:%d, Len:%d\n" , rd.Size(), rd.Len()) }
type Buffer 1 type Buffer struct { ... }
将 buf 包装成 bytes.Buffer 对象:
1 func NewBuffer (buf []byte ) *Buffer
将 s 转换为 []byte 后,包装成 bytes.Buffer 对象:
1 func NewBufferString (s string ) *Buffer
Buffer 本身就是一个缓存(内存块),没有底层数据,缓存的容量会根据需要自动调整。大多数情况下,使用 new(Buffer) 就足以初始化一个 Buffer 了。
bytes.Buffer 实现了如下接口:
1 2 3 4 5 6 io .ReadWriter io .ReaderFrom io .WriterTo io .ByteWeriter io .ByteScanner io .RuneScanner
未读取部分的数据长度:
1 func (b *Buffer) Len () int
缓存的容量:
1 func (b *Buffer) Cap () int
读取前 n 字节的数据并以切片形式返回,如果数据长度小于 n,则全部读取。 切片只在下一次读写操作前合法。
1 func (b *Buffer) Next (n int ) []byte
读取第一个 delim 及其之前的内容,返回遇到的错误(一般是 io.EOF):
1 2 func (b *Buffer) ReadBytes (delim byte ) (line []byte , err error) func (b *Buffer) ReadString (delim byte ) (line string , err error)
写入 r 的 UTF-8 编码,返回写入的字节数和 nil。 保留 err 是为了匹配 bufio.Writer 的 WriteRune 方法。
1 func (b *Buffer) WriteRune (r rune ) (n int , err error)
写入 s,返回写入的字节数和 nil:
1 func (b *Buffer) WriteString (s string ) (n int , err error)
引用未读取部分的数据切片(不移动读取位置):
1 func (b *Buffer) Bytes () []byte
返回未读取部分的数据字符串(不移动读取位置):
1 func (b *Buffer) String () string
自动增加缓存容量,以保证有 n 字节的剩余空间。 如果 n 小于 0 或无法增加容量则会 panic。
1 func (b *Buffer) Grow (n int )
将数据长度截短到 n 字节,如果 n 小于 0 或大于 Cap 则 panic:
1 func (b *Buffer) Truncate (n int )
重设缓冲区,清空所有数据(包括初始内容):
1 func (b *Buffer) Reset ()
eg.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 func main () { rd := bytes.NewBufferString("Hello World!" ) buf := make ([]byte , 6 ) b := rd.Bytes() rd.Read(buf) fmt.Printf("%s\n" , rd.String()) fmt.Printf("%s\n\n" , b) rd.Write([]byte ("abcdefg" )) fmt.Printf("%s\n" , rd.String()) fmt.Printf("%s\n\n" , b) rd.Read(buf) fmt.Printf("%s\n" , rd.String()) fmt.Printf("%s\n" , b) }
errors 包Go 语言使用 error 类型来返回函数执行过程中遇到的错误,如果返回的 error 值为 nil,则表示未遇到错误,否则 error 会返回一个字符串,用于说明遇到了什么错误。
其实 error 只是一个接口,定义如下:
1 2 3 type error interface { Error() string }
你可以用任何类型去实现它(只要添加一个 Error() 方法即可),也就是说,error 可以是任何类型,这意味着,函数返回的 error 值实际可以包含任意信息,不一定是字符串(当然字符串是必须的)。
error 不一定表示一个错误,它可以表示任何信息,比如 io 包中就用 error 类型的 io.EOF 表示数据读取结束,而不是遇到了什么错误。再比如 path/filepath 包中用 error 类型的 filepath.SkipDir 表示跳过当前目录,继续遍历下一个目录,而不是遇到了什么错误。
error.New()函数errors 包实现了一个最简单的 error 类型,只包含一个字符串,它可以记录大多数情况下遇到的错误信息。errors 包的用法也很简单,只有一个 New 函数,用于生成一个最简单的 error 对象:
1 2 func New (text string ) error
eg:
1 2 3 4 5 6 func SomeFunc () error { if 遇到错误 { return errors.New("遇到了某某错误" ) } return nil }
自定义error类型 如果你的程序需要记录更多的错误信息,比如时间、数值等信息,可以声明一个自定义的 error 类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 package mainimport ( "fmt" "time" ) type myError struct { err string time time.Time count int } func (m *myError) Error () string { return fmt.Sprintf("%s %d 次。时间:%v" , m.err, m.count, m.time) } func newErr (s string , i int ) *myError { return &myError{ err: s, time: time.Now(), count: i, } } var count int func SomeFunc () error { if true { count++ return newErr("遇到某某情况" , count) } return nil } func main () { for i := 0 ; i < 5 ; i++ { if err := SomeFunc(); err != nil { fmt.Println(err) } } }
fmt 包实现了格式化I/O函数。文档
占位符 通用占位符:
1 2 3 4 %v 值的默认格式。当打印结构体时,“加号”标记(%+v)会添加字段名%#v 相应值的Go语法表示%T 相应值的类型的Go语法表示% % 字面上的百分号,并非值的占位符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package main import ( "fmt" ) type Sample struct { a int str string } func main () { s := new (Sample) s.a = 1 s.str = "hello" fmt.Printf("%v\n" , *s) fmt.Printf("%+v\n" , *s) fmt.Printf("%#v\n" , *s) fmt.Printf("%T\n" , *s) fmt.Printf("%%\n" , s.a) }
布尔值:
整数值:
1 2 3 4 5 6 7 8 %b 二进制表示%c 相应Unicode码点所表示的字符%d 十进制表示%o 八进制表示%q 单引号围绕的字符字面值,由Go语法安全地转义%x 十六进制表示,字母形式为小写 a-f%X 十六进制表示,字母形式为大写 A-F%U Unicode格式:U+1234,等同于 "U+%04X"
浮点及复数:
1 2 3 4 5 6 %b 无小数部分的,指数为二的幂的科学计数法,与 strconv.FormatFloat中的 'b' 转换格式一致。例如 -123456p-78%e 科学计数法,例如 -1234.456e+78%E 科学计数法,例如 -1234.456E+78%f 有小数点而无指数,例如 123.456%g 根据情况选择 %e 或 %f 以产生更紧凑的(无末尾的0)输出%G 根据情况选择 %E 或 %f 以产生更紧凑的(无末尾的0)输出
字符串和bytes的slice表示:
1 2 3 4 %s 字符串或切片的无解译字节%q 双引号围绕的字符串,由Go语法安全地转义%x 十六进制,小写字母,每字节两个字符%X 十六进制,大写字母,每字节两个字符
指针:
这里没有 ‘u’ 标记。若整数为无符号类型,他们就会被打印成无符号的。类似地,这里也不需要指定操作数的大小(int8,int64)。
对于%v来说默认的格式是:
1 2 3 4 5 6 7 bool: %t int , int8 etc.: %duint, uint8 etc.: %d, %x if printed with %#v float32, complex64, etc: %g string : %schan: %p pointer: %p
对于复合对象,里面的元素使用如下规则进行打印:
1 2 3 4 struct: {field0 field1 ...}array, slice: [elem0 elem1 ...] maps: map[key1: value1 key2: value2]pointer to above: &{}, &[], &map[]
宽度和精度: 宽度是在%之后的值,如果没有指定,则使用该值的默认值,精度是跟在宽度之后的值,如果没有指定,也是使用要打印的值的默认精度.例如:%9.2f,宽度9,精度2
1 2 3 4 5 %f: default width, default precision %9f width 9, default precision %.2f default width, precision 2 %9.2f width 9, precision 2 %9.f width 9, precision 0
对数值而言,宽度为该数值占用区域的最小宽度;精度为小数点之后的位数。但对于 %g/%G 而言,精度为所有数字的总数。例如,对于123.45,格式 %6.2f会打印123.45,而 %.4g 会打印123.5。%e 和 %f 的默认精度为6;但对于 %g 而言,它的默认精度为确定该值所必须的最小位数。
对大多数值而言,宽度为输出的最小字符数,如果必要的话会为已格式化的形式填充空格。对字符串而言,精度为输出的最大字符数,如果必要的话会直接截断。
宽度是指”必要的最小宽度”. 若结果字符串的宽度超过指定宽度时, 指定宽度就会失效。
其他标志:
1 2 3 4 5 6 + 总打印数值的正负号;对于%q(%+q)保证只输出ASCII编码的字符。 - 左对齐 # 备用格式:为八进制添加前导 0 (%#o),为十六进制添加前导 0 x(%#x)或0 X(%#X),为 %p(%#p)去掉前导 0 x;对于 %q,若 strconv.CanBackquote 返回 true,就会打印原始(即反引号围绕的)字符串;如果是可打印字符,%U(%#U)会写出该字符的Unicode编码形式(如字符 x 会被打印成 U+0078 'x' )。 ' ' (空格)为数值中省略的正负号留出空白(% d);以十六进制(% x, % X)打印字符串或切片时,在字节之间用空格隔开0 填充前导的0 而非空格;对于数字,这会将填充移到正负号之后
对于每一个 Printf 类的函数,都有一个 Print 函数,该函数不接受任何格式化,它等价于对每一个操作数都应用 %v。另一个变参函数 Println 会在操作数之间插入空白,并在末尾追加一个换行符
格式化错误:
如果给占位符提供了无效的实参(如将一个字符串提供给%d),便会出现格式化错误.所有的错误都始于“%!”,有时紧跟着单个字符(占位符),并以小括号括住的描述结尾。
Scanning 一组类似的函数通过扫描已格式化的文本来产生值。
Scan、Scanf 和 Scanln 从os.Stdin 中读取; Fscan、Fscanf 和 Fscanln 从指定的 io.Reader 中读取; Sscan、Sscanf 和 Sscanln 从实参字符串中读取。 Scanln、Fscanln 和 Sscanln在换行符处停止扫描,且需要条目紧随换行符之后; Scanf、Fscanf 和 Sscanf需要输入换行符来匹配格式中的换行符; 其它函数则将换行符视为空格。
Scanf、Fscanf 和 Sscanf 根据格式字符串解析实参,类似于 Printf。例如,%x会将一个整数扫描为十六进制数,而 %v 则会扫描该值的默认表现格式。
格式化类似于 Printf,但也有例外,如下所示:
1 2 3 4 5 %p 没有实现 %T 没有实现 %e %E %f %F %g %G 都完全等价,且可扫描任何浮点数或复合数值 %s 和 %v 在扫描字符串时会将其中的空格作为分隔符 标记
在输入Scanf中,宽度可以理解成输入的文本(%5s表示输入5个字符),而Scanf没有精度这种说法(没有%5.2f,只有 %5f)
函数 Errorf 1 func Errorf (format string , a ...interface {}) error
Errorf 根据于格式说明符进行格式化,并将字符串作为满足 error 的值返回,其返回类型是error(功能同Sprintf,只不过把结果字符串包装成error类型).
1 2 3 func main () { a := fmt.Errorf("%s%d" , "error:" , 1 ) fmt.Println(a)
Fprint、Fprintf、Fprintln 对于每一个 Printf 类的函数,都有一个 Print 函数,该函数不接受任何格式化,它等价于对每一个操作数都应用 %v。另一个变参函数 Println 会在操作数之间插入空白,并在末尾追加一个换行符
1 2 3 func Fprint (w io.Writer, a ...interface {}) (n int , err error) func Fprintf (w io.Writer, format string , a ...interface {}) (n int , err error) func Fprintln (w io.Writer, a ...interface {}) (n int , err error)
Fprint 使用其操作数的默认格式进行格式化并写入到 w。当两个连续的操作数均不为字符串时,它们之间就会添加空格。它返回写入的字节数以及任何遇到的错误。 Fprintf 根据于格式说明符进行格式化并写入到 w。它返回写入的字节数以及任何遇到的写入错误。 Fprintln 使用其操作数的默认格式进行格式化并写入到 w。其操作数之间总是添加空格,且总在最后追加一个换行符。它返回写入的字节数以及任何遇到的错误。
1 2 3 4 5 6 func main () { a := "asdf" fmt.Fprintln(os.Stdout, a) fmt.Fprintf(os.Stdout, "%.2s\n" , a) fmt.Fprint(os.Stdout, a) }
Fscan、Fscanf、Fscanln 1 2 3 func Fscan (r io.Reader, a ...interface {}) (n int , err error) func Fscanf (r io.Reader, format string , a ...interface {}) (n int , err error) func Fscanln (r io.Reader, a ...interface {}) (n int , err error)
Fscan 扫描从 r 中读取的文本,并将连续由空格分隔的值存储为连续的实参。换行符计为空格。它返回成功扫描的条目数。若它少于实参数,err 就会报告原因。 Fscanf 扫描从 r 中读取的文本,并将连续由空格分隔的值存储为连续的实参,其格式由 format 决定。它返回成功解析的条目数。 Fscanln 类似于 Sscan,但它在换行符处停止扫描,且最后的条目之后必须为换行符或 EOF。 注:Fscan类的也是由空格进行分割的.
1 2 3 4 5 6 7 8 9 10 11 func main () { r := strings.NewReader("hello 1" ) var a string var b int fmt.Fscanln(r, &a, &b) fmt.Println(a, b) r1 := strings.NewReader("helloworld 2" ) fmt.Fscanf(r1, "hello%s%d" , &a, &b) fmt.Println(a, b) }
Print、Printf、Println 1 2 3 func Print (a ...interface {}) (n int , err error) func Printf (format string , a ...interface {}) (n int , err error) func Println (a ...interface {}) (n int , err error)
Print 使用其操作数的默认格式进行格式化并写入到标准输出。当两个连续的操作数均不为字符串时,它们之间就会添加空格。它返回写入的字节数以及任何遇到的错误。 Printf 根据格式说明符进行格式化并写入到标准输出。它返回写入的字节数以及任何遇到的写入错误。 使用其操作数的默认格式进行格式化并写入到标准输出。其操作数之间总是添加空格,且总在最后追加一个换行符。它返回写入的字节数以及任何遇到的错误。
1 2 3 4 5 6 7 func main () { s := "hello,world!" fmt.Println(s) fmt.Printf("%s\n" , s) fmt.Print(s) }
类似于 Fprint(os.Stdout,...)
Scan、Scanf、Scanln 1 2 3 func Scan (a ...interface {}) (n int , err error) func Scanf (format string , a ...interface {}) (n int , err error) func Scanln (a ...interface {}) (n int , err error)
Scan 扫描从标准输入中读取的文本,并将连续由空格分隔的值存储为连续的实参。换行符计为空格。它返回成功扫描的条目数。若它少于实参数,err 就会报告原因。 Scanf 扫描从标准输入中读取的文本,并将连续由空格分隔的值存储为连续的实参,其格式由 format 决定。它返回成功扫描的条目数。 Scanln 类似于 Scan,但它在换行符处停止扫描,且最后的条目之后必须为换行符或 EOF。
1 2 3 4 5 6 7 8 func main () { var a string var b int fmt.Scanln(&a, &b) fmt.Println(a, b) fmt.Scanf("%s%d" , &a, &b) fmt.Println(a, b) }
Sprint、Sprintf、Sprintln 1 2 3 func Sprint (a ...interface {}) string func Sprintf (format string , a ...interface {}) string func Sprintln (a ...interface {}) string
Sprint 使用其操作数的默认格式进行格式化并返回其结果字符串。当两个连续的操作数均不为字符串时,它们之间就会添加空格。 Sprintf 根据于格式说明符进行格式化并返回其结果字符串。 Sprintln 使用其操作数的默认格式进行格式化并写返回其结果字符串。其操作数之间总是添加空格,且总在最后追加一个换行符。
1 2 3 4 func main () { a := fmt.Sprintf("%s,%d" , "hello" , 1 ) fmt.Println(a) }
Sscan、Sscanf、Sscanln 1 2 3 func Sscan (str string , a ...interface {}) (n int , err error) func Sscanf (str string , format string , a ...interface {}) (n int , err error) func Sscanln (str string , a ...interface {}) (n int , err error)
Sscan 扫描实参 string,并将连续由空格分隔的值存储为连续的实参。换行符计为空格。它返回成功扫描的条目数。若它少于实参数,err 就会报告原因。 Scanf 扫描实参 string,并将连续由空格分隔的值存储为连续的实参,其格式由 format 决定。它返回成功解析的条目数。 Sscanln 类似于 Sscan,但它在换行符处停止扫描,且最后的条目之后必须为换行符或 EOF。
1 2 3 4 5 6 7 8 9 func main () { var a string var b int var c int fmt.Sscan("hello 1" , &a, &b) fmt.Println(a, b) fmt.Sscanf("helloworld 2 " , "hello%s%d" , &a, &c) fmt.Println(a, c) }
type 用于实现对象的自定义格式输出
1 2 3 4 5 6 type Formatter interface { Format(f State, c rune ) }
type GoStringer 1 2 3 4 type GoStringer interface { GoString() string }
type ScanState ScanState 会返回扫描状态给自定义的 Scanner Scanner 可能会做字符的实时扫描 或者通过 ScanState 获取以空格分割的 token
1 2 3 4 type ScanState interface { }
如果在 Scanln、Fscanln 或 Sscanln 中调用该方法 该方法会在遇到 ‘\n’ 或读取超过指定的宽度时返回 EOFReadRune() (r rune, size int, err error) UnreadRune 撤消最后一次的 ReadRune 操作UnreadRune() error SkipSpace 跳过输入数据中的空格 在 Scanln、Fscanln、Sscanln 操作中,换行符会被当作 EOF 在其它 Scan 操作中,换行符会被当作空格SkipSpace() 如果参数 skipSpace 为 true,则 Token 会跳过输入数据中的空格 然后返回满足函数 f 的连续字符,如果 f 为 nil,则使用 !unicode.IsSpace 来代替 f 在 Scanln、Fscanln、Sscanln 操作中,换行符会被当作 EOF 在其它 Scan 操作中,换行符会被当作空格 返回的 token 是一个切片,返回的数据可能在下一次调用 Token 的时候被修改Token(skipSpace bool, f func(rune) bool) (token []byte, err error) Width 返回宽度值以及宽度值是否被设置Width() (wid int, ok bool) 因为 ReadRune 已经通过接口实现,所以 Read 可能永远不会被 Scan 例程调用 一个 ScanState 的实现,可能会选择废弃 Read 方法,而使其始终返回一个错误信息Read(buf []byte) (n int, err error)}
type Scanner Scanner 由任何拥有 Scan 方法的值实现,它将输入扫描成值的表示,并将其结果存储到接收者中,该接收者必须为可用的指针。Scan 方法会被 Scan、Scanf 或 Scanln 的任何实现了它的实参所调用。
1 2 3 type Scanner interface { Scan(state ScanState, verb rune ) error }
type State 1 2 3 4 5 6 7 8 9 10 11 12 13 14 type State interface { Write(b []byte ) (ret int , err error) Width() (wid int , ok bool ) Precision() (prec int , ok bool ) Flag(c int ) bool }
type Stringer 1 2 3 4 type Stringer interface { String() string }
net/http 包文档
http包包含http客户端和服务端的实现,利用Get,Head,Post,以及PostForm实现HTTP或者HTTPS的请求。
当客户端使用完response body后必须使用close对其进行关闭:
1 2 3 4 5 6 7 resp, err := http.Get("http://example.com/" ) if err != nil { } defer resp.Body.Close()body, err := ioutil.ReadAll(resp.Body)
变量 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 var ( ErrHeaderTooLong = &ProtocolError{"header too long" } ErrShortBody = &ProtocolError{"entity body too short" } ErrNotSupported = &ProtocolError{"feature not supported" } ErrUnexpectedTrailer = &ProtocolError{"trailer header without chunked transfer encoding" } ErrMissingContentLength = &ProtocolError{"missing ContentLength in HEAD response" } ErrNotMultipart = &ProtocolError{"request Content-Type isn't multipart/form-data" } ErrMissingBoundary = &ProtocolError{"no multipart boundary param in Content-Type" } ) var ( ErrWriteAfterFlush = errors.New("Conn.Write called after Flush" ) ErrBodyNotAllowed = errors.New("http: request method or response status code does not allow body" ) ErrHijacked = errors.New("Conn has been hijacked" ) ErrContentLength = errors.New("Conn.Write wrote more than the declared Content-Length" ) ) var DefaultClient = &Client{} var DefaultServeMux = NewServeMux()var ErrBodyReadAfterClose = errors.New("http: invalid Read on closed Body" )var ErrHandlerTimeout = errors.New("http: Handler timeout" )var ErrLineTooLong = internal.ErrLineTooLongvar ErrMissingFile = errors.New("http: no such file" )var ErrNoCookie = errors.New("http: named cookie not present" )var ErrNoLocation = errors.New("http: no Location header in response" )
函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 func CanonicalHeaderKey (s string ) string //返回header key 的规范化形式,规范化形式是以"-"为分隔符,每一部分都是首字母大写,其他字母小写.例如"accept -encoding " 的标准化形式是 "Accept -Encoding ".func DetectContentType (data []byte ) string //检查给定数据的内容类型Content -Type ,最多检测512byte 数据,如果有效的话,该函数返回一个MIME 类型,否则的话,返回一个"application /octet -stream "func Error (w ResponseWriter, error string , code int ) //利用指定的错误信息和Http code 来响应请求,其中错误信息必须是纯文本.func NotFound (w ResponseWriter, r *Request) //返回HTTP404 not found 错误func Handle (pattern string , handler Handler) //将handler 按照指定的格式注册到DefaultServeMux ,ServeMux 解释了模式匹配规则func HandleFunc (pattern string , handler func (ResponseWriter, *Request) )//同上,主要用来实现动态文件内容的展示,这点与ServerFile () 不同的地方。func ListenAndServe (addr string , handler Handler) error //监听TCP 网络地址addr 然后调用具有handler 的Serve 去处理连接请求.通常情况下Handler 是nil ,使用默认的DefaultServeMux func ListenAndServeTLS (addr string , certFile string , keyFile string , handler Handler) error //该函数与ListenAndServe 功能基本相同,二者不同之处是该函数需要HTTPS 连接.也就是说,必须给该服务Serve 提供一个包含整数的秘钥的文件,如果证书是由证书机构签署的,那么证书文件必须是服务证书之后跟着CA 证书.func ServeFile (w ResponseWriter, r *Request, name string ) //利用指定的文件或者目录的内容来响应相应的请求.func SetCookie (w ResponseWriter, cookie *Cookie) //给w 设定cookie func StatusText (code int ) string //对于http 状态码返回文本表示,如果这个code 未知,则返回空的字符串.
eg.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package mainimport ( "fmt" "net/http" ) func Test (w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "1.txt" ) cookie := &http.Cookie{ Name: http.CanonicalHeaderKey("uid-test" ), Value: "1234" , } r.AddCookie(cookie) fmt.Println(r.Cookie("uid-test" )) fmt.Println(r.Cookie("Uid-Test" )) fmt.Println(r.Cookies()) } func main () { stat := http.StatusText(200 ) fmt.Println(stat) stringtype := http.DetectContentType([]byte ("test" )) fmt.Println(stringtype) http.HandleFunc("/test" , Test) err := http.ListenAndServe(":9999" , nil ) if err != nil { fmt.Println(err) } }
1 2 3 4 5 6 7 8 9 10 func MaxBytesReader (w ResponseWriter, r io.ReadCloser, n int64 ) io .ReadCloser //该函数类似于io .LimitReader 但是该函数是用来限制请求体的大小.与io .LimitReader 不同的是,该函数返回一个ReaderCloser ,当读超过限制时,返回一个non -EOF ,并且当Close 方法调用时,关闭底层的reader .该函数组织客户端恶意发送大量请求,浪费服务器资源.func ParseHTTPVersion (vers string ) (major, minor int , ok bool ) //解析http 字符串版本进行解析,"HTTP /1.0" 返回 (1, 0, true ) //注解析的字符串必须以HTTP 开始才能够正确解析,HTTP 区分大小写,其他诸如http 或者Http 都不能够正确解析。func ParseTime (text string ) (t time.Time, err error) //解析时间头(例如data:header) ,解析格式如下面三种(HTTP/1.1中允许的) :TimeFormat , time .RFC850 , and time .ANSIC func ProxyFromEnvironment (req *Request) (*url.URL, error) //该函数返回一个指定请求的代理URL ,这是由环境变量HTTP_PROXY ,HTTPS_PROXY 以及NO_PROXY 决定的,对于https 请求,HTTPS_PROXY 优先级高于HTTP_PROXY ,环境值可能是一个URL 或者一个host :port ,其中这两种类型都是http 调度允许的,如果不是这两种类型的数值便会返回错误.如果在环境中没有定义代理或者代理不应该用于该请求(定义为NO_PROXY) ,将会返回一个nil URL 和一个nil error .作为一个特例,如果请求rul 是"localhost ",无论有没有port ,那么将返回一个nil rul 和一个nil error .func ProxyURL (fixedURL *url.URL) func (*Request) (*url.URL, error) //返回一个用于传输的代理函数,该函数总是返回相同的URL func Redirect (w ResponseWriter, r *Request, urlStr string , code int ) //返回一个重定向的url 给指定的请求,这个重定向url 可能是一个相对请求路径的一个相对路径.func Serve (l net.Listener, handler Handler) error //该函数接受listener l 的传入http 连接,对于每一个连接创建一个新的服务协程,这个服务协程读取请求然后调用handler 来给他们响应.handler 一般为nil ,这样默认的DefaultServeMux 被使用.func ServeContent (w ResponseWriter, req *Request, name string , modtime time.Time, content io.ReadSeeker) //该函数使用提供的ReaderSeeker 提供的内容来恢复请求,该函数相对于io .Copy 的优点是可以处理范围类请求,设定MIME 类型,并且处理了If -Modified -Since 请求.如果未设定content -type 类型,该函数首先通过文件扩展名来判断类型,如果失效的话,读取content 的第一块数据并将他传递给DetectContentType 进行类型判断.name 可以不被使用,更进一步说,他可以为空并且不在respone 中返回.如果modtime 不是0时间,该时间则体现在response 的最后一次修改的header 中,如果请求包括一个If -Modified -Since header ,该函数利用modtime 来决定是否发送该content .该函数利用Seek 功能来决定content 的大小.
type Client 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 type Clienttype Client struct { Transport RoundTripper CheckRedirect func (req *Request, via []*Request) error Jar CookieJar Timeout time.Duration }
Client的方法:
1 2 3 4 5 6 7 8 9 func (c *Client) Do (req *Request) (resp *Response, err error) //Do 发送http 请求并且返回一个http 响应,遵守client 的策略,如重定向,cookies 以及auth 等.错误经常是由于策略引起的,当err 是nil 时,resp 总会包含一个非nil 的resp .body .当调用者读完resp .body 之后应该关闭它,如果resp .body 没有关闭,则Client 底层RoundTripper 将无法重用存在的TCP 连接去服务接下来的请求,如果resp .body 非nil ,则必须对其进行关闭.通常来说,经常使用Get ,Post ,或者PostForm 来替代Do .func (c *Client) Get (url string ) (resp *Response, err error) func (c *Client) Head (url string ) (resp *Response, err error) func (c *Client) Post (url string , bodyType string , body io.Reader) (resp *Response, err error) func (c *Client) PostForm (url string , data url.Values) (resp *Response, err error)
http中Client客户端的参数设定解析如上面描述所示,Client具有Do,Get,Head,Post以及PostForm等方法。 其中Do方法可以对Request进行一系列的设定,而其他的对request设定较少。如果Client使用默认的Client,则其中的Get,Head,Post以及PostForm方法相当于默认的http.Get,http.Post,http.Head以及http.PostForm函数。举例说明其用法。其中Get,Head,Post以及PostForm用法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 package mainimport ( "bytes" "fmt" "io/ioutil" "net/http" "net/url" ) func main () { requestUrl := "http://www.baidu.com" postvalue := url.Values{ "username" : {"xiaoming" }, "address" : {"beijing" }, "subject" : {"Hello" }, "from" : {"china" }, } body := bytes.NewBufferString(postvalue.Encode()) request, err := http.Post(requestUrl, "text/html" , body) if err != nil { fmt.Println(err) } defer request.Body.Close() fmt.Println(request.StatusCode) if request.StatusCode == 200 { rb, err := ioutil.ReadAll(request.Body) if err != nil { fmt.Println(rb) } fmt.Println(string (rb)) } }
Do方法可以灵活的对request进行配置,然后进行请求。利用http.Client以及http.NewRequest来模拟请求。模拟request中带有cookie的请求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package mainimport ( "fmt" "io/ioutil" "net/http" "strconv" ) func main () { client := &http.Client{} request, err := http.NewRequest("GET" , "http://www.baidu.com" , nil ) if err != nil { fmt.Println(err) } cookie := &http.Cookie{Name: "userId" , Value: strconv.Itoa(12345 )} request.AddCookie(cookie) request.Header.Set("Accept" , "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" ) request.Header.Set("Accept-Charset" , "GBK,utf-8;q=0.7,*;q=0.3" ) request.Header.Set("Accept-Encoding" , "gzip,deflate,sdch" ) request.Header.Set("Accept-Language" , "zh-CN,zh;q=0.8" ) request.Header.Set("Cache-Control" , "max-age=0" ) request.Header.Set("Connection" , "keep-alive" ) response, err := client.Do(request) if err != nil { fmt.Println(err) return } defer response.Body.Close() fmt.Println(response.StatusCode) if response.StatusCode == 200 { r, err := ioutil.ReadAll(response.Body) if err != nil { fmt.Println(err) } fmt.Println(string (r)) } }
type CloseNotifier 接口 1 2 3 4 5 type CloseNotifiertype CloseNotifier interface { CloseNotify() <-chan bool }
CloseNotifier经常被ResponseWriter用来检测底层连接是否已经断开,举例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 func Test (w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "test.go" ) var closenotify http.CloseNotifier closenotify = w.(http.CloseNotifier) select { case <-closenotify.CloseNotify(): fmt.Println("cut" ) case <-time.After(time.Duration(100 ) * time.Second): fmt.Println("timeout" ) } } func main () { http.HandleFunc("/test" , Test) err := http.ListenAndServe(":9999" , nil ) if err != nil { fmt.Println(err) } }
type ConnState int 1 2 type ConnState type ConnState int
其中ConnState常用状态变量如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const ( StateNew ConnState = iota StateActive StateIdle StateHijacked StateClosed )
1 2 3 func (c ConnState) String () string //状态的字符形式表示fmt.Println(http.StateActive) fmt.Println(http.StateActive.String())
type Cookie struct type Cookie//常用SetCooker用来给http的请求或者http的response设置cookie
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 type Cookie struct { Name string Value string Path string Domain string Expires time.Time RawExpires string MaxAge int Secure bool HttpOnly bool Raw string Unparsed []string }
func (c *Cookie) String() string//该函数返回cookie的序列化结果。如果只设置了Name和Value字段,序列化结果可用于HTTP请求的Cookie头或者HTTP回复的Set-Cookie头;如果设置了其他字段,序列化结果只能用于HTTP回复的Set-Cookie头。
type CookieJar//在http请求中,CookieJar管理存储和使用cookies.Cookiejar的实现必须被多协程并发使用时是安全的.
1 2 3 4 5 6 7 type CookieJar interface { SetCookies(u *url.URL, cookies []*Cookie) Cookies(u *url.URL) []*Cookie }
type Dir string type Dir//使用一个局限于指定目录树的本地文件系统实现一个文件系统.一个空目录被当做当前目录”.”
1 2 type Dir string func (d Dir) Open (name string ) (File, error)
type File 接口 type File //File是通过FileSystem的Open方法返回的,并且能够被FileServer实现.该方法与*os.File行为表现一样.
1 2 3 4 5 6 7 type File interface { io.Closer io.Reader Readdir(count int ) ([]os.FileInfo, error) Seek(offset int64 , whence int ) (int64 , error) Stat() (os.FileInfo, error) }
type FileSystem 接口
type FileSystem//实现了对一系列指定文件的访问,其中文件路径之间通过分隔符进行分割.
1 2 3 type FileSystem interface { Open(name string ) (File, error) }
type Flusher 接口 type Flusher //responsewriters允许http控制器将缓存数据刷新入client.然而如果client是通过http代理连接服务器,这个缓存数据也可能是在整个response结束后才能到达客户端.
1 2 3 4 type Flusher interface { Flush() }
type Handler 接口 type Handler //实现Handler接口的对象可以注册到HTTP服务端,为指定的路径或者子树提供服务。ServeHTTP应该将回复的header和数据写入ResponseWriter接口然后返回。返回意味着该请求已经结束,HTTP服务端可以转移向该连接上的下一个请求。
//如果ServeHTTP崩溃panic,那么ServeHTTP的调用者假定这个panic的影响与活动请求是隔离的,二者互不影响.调用者恢复panic,将stack trace记录到错误日志中,然后挂起这个连接.
1 2 3 type Handler interface { ServeHTTP(ResponseWriter, *Request) }
func FileServer(root FileSystem) Handler // FileServer返回一个使用FileSystem接口提供文件访问服务的HTTP处理器。可以使用httpDir来使用操作系统的FileSystem接口实现。其主要用来实现静态文件的展示。
func NotFoundHandler() Handler //返回一个简单的请求处理器,该处理器对任何请求都会返回”404 page not found”
func RedirectHandler(url string, code int) Handler//使用给定的状态码将它接受到的任何请求都重定向到给定的url
func StripPrefix(prefix string, h Handler) Handler//将请求url.path中移出指定的前缀,然后将省下的请求交给handler h来处理,对于那些不是以指定前缀开始的路径请求,该函数返回一个http 404 not found 的错误.
func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler //具有超时限制的handler,该函数返回的新Handler调用h中的ServerHTTP来处理每次请求,但是如果一次调用超出时间限制,那么就会返回给请求者一个503服务请求不可达的消息,并且在ResponseWriter返回超时错误.
其中FileServer经常和StripPrefix一起连用,用来实现静态文件展示,举例如下:
1 2 3 4 5 6 func main () { http.Handle("/test/" , http.FileServer(http.Dir("/home/work/" ))) http.Handle("/download/" , http.StripPrefix("/download/" , http.FileServer(http.Dir("/home/work/" )))) http.Handle("/tmpfiles/" , http.StripPrefix("/tmpfiles/" , http.FileServer(http.Dir("/tmp" )))) http.ListenAndServe(":9999" , nil ) }
type HandlerFunc type HandlerFunc//HandlerFunc type是一个适配器,通过类型转换我们可以将普通的函数作为HTTP处理器使用。如果f是一个具有适当签名的函数,HandlerFunc(f)通过调用f实现了Handler接口。
1 type HandlerFunc func (ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) //ServeHttp调用f(w,r)
type Header//代表在http header中的key-value对
1 type Header map [string ][]string
1 2 3 4 5 6 func (h Header) Add (key, value string ) //将key ,value 组成键值对添加到header 中func (h Header) Del (key string ) //header 中删除对应的key -value 对func (h Header) Get (key string ) string //获取指定key 的第一个value ,如果key 没有对应的value ,则返回"",为了获取一个key 的多个值,用CanonicalHeaderKey 来获取标准规范格式.func (h Header) Set (key, value string ) //给一个key 设定为相应的value .func (h Header) Write (w io.Writer) error //利用线格式来写header func (h Header) WriteSubset (w io.Writer, exclude map [string ]bool ) error //利用线模式写header ,如果exclude 不为nil ,则在exclude 中包含的exclude [key ] == true 不被写入.
type Hijacker 接口 1 2 3 4 type Hijacker interface { Hijack() (net.Conn, *bufio.ReadWriter, error) }
eg.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 func HiJack (w http.ResponseWriter, r *http.Request) { hj, ok := w.(http.Hijacker) if !ok { http.Error(w, "webserver doesn't support hijacking" , http.StatusInternalServerError) return } conn, bufrw, err := hj.Hijack() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } defer conn.Close() bufrw.WriteString("Now we're speaking raw TCP. Say hi: \n" ) bufrw.Flush() fmt.Fprintf(bufrw, "You said: %s Bye.\n" , "Good" ) bufrw.Flush() } func main () { http.HandleFunc("/hijack" , HiJack) err := http.ListenAndServe(":9999" , nil ) if err != nil { fmt.Println(err) } }
type ProtocolError type ProtocolError //http请求解析错误
1 func (err *ProtocolError) Error () string
type Reques struct type Request//代表客户端给服务器端发送的一个请求.该字段在服务器端和客户端使用时区别很大.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 type Request struct { Method string URL *url.URL Proto string ProtoMajor int ProtoMinor int Header Header Body io.ReadCloser ContentLength int64 TransferEncoding []string Close bool Host string Form url.Values PostForm url.Values MultipartForm *multipart.Form Trailer Header RemoteAddr string RequestURI string TLS *tls.ConnectionState }
func NewRequest(method, urlStr string, body io.Reader) (*Request, error) //利用指定的method,url以及可选的body返回一个新的请求.如果body参数实现了io.Closer接口,Request返回值的Body 字段会被设置为body,并会被Client类型的Do、Post和PostForm方法以及Transport.RoundTrip方法关闭。
func ReadRequest(b *bufio.Reader) (req *Request, err error)//从b中读取和解析一个请求.
func (r *Request) AddCookie(c *Cookie) //给request添加cookie,AddCookie向请求中添加一个cookie.按照RFC 6265 section 5.4的规则,AddCookie不会添加超过一个Cookie头字段.这表示所有的cookie都写在同一行,用分号分隔(cookie内部用逗号分隔属性)
func (r Request) Cookie(name string) ( Cookie, error)//返回request中指定名name的cookie,如果没有发现,返回ErrNoCookie
func (r Request) Cookies() [] Cookie//返回该请求的所有cookies
func (r *Request) SetBasicAuth(username, password string)//利用提供的用户名和密码给http基本权限提供具有一定权限的header。当使用http基本授权时,用户名和密码是不加密的
func (r *Request) UserAgent() string//如果在request中发送,该函数返回客户端的user-Agent
用法eg.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 package mainimport ( "fmt" "io/ioutil" "net/http" ) func Test () { req, err := http.NewRequest("GET" , "http://www.baidu.com" , nil ) if err != nil { fmt.Println(err) return } req.SetBasicAuth("test" , "123456" ) fmt.Println(req.Proto) cookie := &http.Cookie{ Name: "test" , Value: "12" , } req.AddCookie(cookie) fmt.Println(req.Cookie("test" )) fmt.Println(req.Cookies()) req.Header.Set("User-Agent" , "useragent" ) fmt.Println(req.UserAgent()) client := &http.Client{} resp, err := client.Do(req) if err != nil { fmt.Println(err) return } defer resp.Body.Close() if resp.StatusCode == 200 { content, _ := ioutil.ReadAll(resp.Body) fmt.Println(string (content)) } } func main () { Test() }
func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error)//对于指定格式的key,FormFile返回符合条件的第一个文件,如果有必要的话,该函数会调用ParseMultipartForm和ParseForm。
func (r *Request) FormValue(key string) string//返回key获取的队列中第一个值。在查询过程中post和put中的主题参数优先级高于url中的value。为了访问相同key的多个值,调用ParseForm然后直接检查RequestForm。
func (r Request) MultipartReader() ( multipart.Reader, error)//如果这是一个有多部分组成的post请求,该函数将会返回一个MIME 多部分reader,否则的话将会返回一个nil和error。使用本函数代替ParseMultipartForm可以将请求body当做流stream来处理。
func (r *Request) ParseForm() error//解析URL中的查询字符串,并将解析结果更新到r.Form字段。对于POST或PUT请求,ParseForm还会将body当作表单解析,并将结果既更新到r.PostForm也更新到r.Form。解析结果中,POST或PUT请求主体要优先于URL查询字符串(同名变量,主体的值在查询字符串的值前面)。如果请求的主体的大小没有被MaxBytesReader函数设定限制,其大小默认限制为开头10MB。ParseMultipartForm会自动调用ParseForm。重复调用本方法是无意义的。
func (r *Request) ParseMultipartForm(maxMemory int64) error //ParseMultipartForm将请求的主体作为multipart/form-data解析。请求的整个主体都会被解析,得到的文件记录最多 maxMemery字节保存在内存,其余部分保存在硬盘的temp文件里。如果必要,ParseMultipartForm会自行调用 ParseForm。重复调用本方法是无意义的。
func (r *Request) PostFormValue(key string) string//返回post或者put请求body指定元素的第一个值,其中url中的参数被忽略。
func (r *Request) ProtoAtLeast(major, minor int) bool//检测在request中使用的http协议是否至少是major.minor
func (r *Request) Referer() string//如果request中有refer,那么refer返回相应的url。Referer在request中是拼错的,这个错误从http初期就已经存在了。该值也可以从Headermap中利用Header[“Referer”]获取;在使用过程中利用Referer这个方法而不是map的形式的好处是在编译过程中可以检查方法的错误,而无法检查map中key的错误。
func (r *Request) Write(w io.Writer) error//Write方法以有线格式将HTTP/1.1请求写入w(用于将请求写入下层TCPConn等)。本方法会考虑请求的如下字段:Host URL Method (defaults to “GET”) Header ContentLength TransferEncoding Body 如果存在Body,ContentLength字段<= 0且TransferEncoding字段未显式设置为[“identity”],Write方法会显式添加”Transfer-Encoding: chunked”到请求的头域。Body字段会在发送完请求后关闭。
func (r *Request) WriteProxy(w io.Writer) error//该函数与Write方法类似,但是该方法写的request是按照http代理的格式去写。尤其是,按照RFC 2616 Section 5.1.2,WriteProxy会使用绝对URI(包括协议和主机名)来初始化请求的第1行(Request-URI行)。无论何种情况,WriteProxy都会使用r.Host或r.URL.Host设置Host头。
type Response struct type Response//指对于一个http请求的响应response
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 type Response struct { Status string StatusCode int Proto string ProtoMajor int ProtoMinor int Header Header Body io.ReadCloser ContentLength int64 TransferEncoding []string Close bool Trailer Header Request *Request TLS *tls.ConnectionState }
func Get(url string) (resp *Response, err error)//利用GET方法对一个指定的URL进行请求,如果response是如下重定向中的一个代码,则Get之后将会调用重定向内容,最多10次重定向。
1 2 3 4 301 (永久重定向,告诉客户端以后应该从新地址访问)302 (暂时性重定向,作为HTTP1.0 的标准,以前叫做Moved Temporarily,现在叫做Found。现在使用只是为了兼容性处理,包括PHP的默认Location重定向用到也是302 ),注:303 和307 其实是对302 的细化。303 (对于Post请求,它表示请求已经被处理,客户端可以接着使用GET方法去请求Location里的URl)307 (临时重定向,对于Post请求,表示请求还没有被处理,客户端应该向Location里的URL重新发起Post请求)
//如果有太多次重定向或者有一个http协议错误将会导致错误。当err为nil时,resp总是包含一个非nil的resp.body,Get是对DefaultClient.Get的一个包装。
func Head(url string) (resp *Response, err error)//该函数功能见net中Head方法功能。该方法与默认的defaultClient中Head方法一致。
func Post(url string, bodyType string, body io.Reader) (resp *Response, err error)//该方法与默认的defaultClient中Post方法一致。
func PostForm(url string, data url.Values) (resp *Response, err error)//该方法与默认的defaultClient中PostForm方法一致。
func ReadResponse(r bufio.Reader, req *Request) ( Response, error)//ReadResponse从r读取并返回一个HTTP 回复。req参数是可选的,指定该回复对应的请求(即是对该请求的回复)。如果是nil,将假设请 求是GET请求。客户端必须在结束resp.Body的读取后关闭它。读取完毕并关闭后,客户端可以检查resp.Trailer字段获取回复的 trailer的键值对。(本函数主要用在客户端从下层获取回复)
func (r Response) Cookies() [] Cookie//解析cookie并返回在header中利用set-Cookie设定的cookie值。
func (r Response) Location() ( url.URL, error)//返回response中Location的header值的url。如果该值存在的话,则对于请求问题可以解决相对重定向的问题,如果该值为nil,则返回ErrNOLocation的错误。
func (r *Response) ProtoAtLeast(major, minor int) bool//判定在response中使用的http协议是否至少是major.minor的形式。
func (r *Response) Write(w io.Writer) error//将response中信息按照线性格式写入w中。
type ResponseWriter 接口
type ResponseWriter//该接口被http handler用来构建一个http response
1 2 3 4 5 6 7 8 9 10 type ResponseWriter interface { Header() Header WriteHeader(int ) Write([]byte ) (int , error) }
type RoundTripper 接口 type RoundTripper//该函数是一个执行简单http事务的接口,该接口在被多协程并发使用时必须是安全的。
1 2 3 4 5 6 7 8 type RoundTripper interface { RoundTrip(*Request) (*Response, error) }
func NewFileTransport(fs FileSystem) RoundTripper //该函数返回一个RoundTripper接口,服务指定的文件系统。 返回的RoundTripper接口会忽略接收的请求中的URL主机及其他绝大多数属性。该函数的典型应用是给Transport类型的值注册”file”协议。如下所示:
1 2 3 4 5 t := &http.Transport{} t.RegisterProtocol("file" , http.NewFileTransport(http.Dir("/" ))) c := &http.Client{Transport: t} res, err := c.Get("file:///etc/passwd" ) ...
*type ServeMux * type ServeMux //该函数是一个http请求多路复用器,它将每一个请求的URL和一个注册模式的列表进行匹配,然后调用和URL最匹配的模式的处理器进行后续操作。模式是固定的、由根开始的路径,如”/favicon.ico”,或由根开始的子树,如”/images/“ (注意结尾的斜杠)。较长的模式优先于较短的模式,因此如果模式”/images/“和”/images/thumbnails/“都注册了处理器,后一 个处理器会用于路径以”/images/thumbnails/“开始的请求,前一个处理器会接收到其余的路径在”/images/“子树下的请求。 注意,因为以斜杠结尾的模式代表一个由根开始的子树,模式”/“会匹配所有的未被其他注册的模式匹配的路径,而不仅仅是路径”/“。
模式也能(可选地)以主机名开始,表示只匹配该主机上的路径。指定主机的模式优先于一般的模式,因此一个注册了两个模式”/codesearch”和”codesearch.google.com/“的处理器不会接管目标为”http://www.google.com/"的请求。
ServeMux还会负责对URL路径的过滤,将任何路径中包含”.”或”..”元素的请求重定向到等价的没有这两种元素的URL。(参见path.Clean函数)
func NewServeMux() *ServeMux //初始化一个新的ServeMux
func (mux *ServeMux) Handle(pattern string, handler Handler) //将handler注册为指定的模式,如果该模式已经有了handler,则会出错panic。
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request))//将handler注册为指定的模式
func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) //根据指定的r.Method,r.Host以及r.RUL.Path返回一个用来处理给定请求的handler。该函数总是返回一个非nil的 handler,如果path不是一个规范格式,则handler会重定向到其规范path。Handler总是返回匹配该请求的的已注册模式;在内建重 定向处理器的情况下,pattern会在重定向后进行匹配。如果没有已注册模式可以应用于该请求,本方法将返回一个内建的”404 page not found”处理器和一个空字符串模式。
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) //该函数用于将最接近请求url模式的handler分配给指定的请求。
举例说明servemux的用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package mainimport ( "fmt" "net/http" ) func Test (w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "just for test!" ) } func main () { mux := http.NewServeMux() mux.Handle("/" , http.FileServer(http.Dir("/home" ))) mux.HandleFunc("/test" , Test) err := http.ListenAndServe(":9999" , mux) if err != nil { fmt.Println(err) } }
type Server struct type Server //该结构体定义一些用来运行HTTP Server的参数,如果Server默认为0的话,那么这也是一个有效的配置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 type Server struct { Addr string Handler Handler ReadTimeout time.Duration WriteTimeout time.Duration MaxHeaderBytes int TLSConfig *tls.Config TLSNextProto map [string ]func (*Server, *tls.Conn, Handler) ConnState func (net.Conn, ConnState) ErrorLog *log.Logger }
func (srv *Server) ListenAndServe() error//监听TCP网络地址srv.Addr然后调用Serve来处理接下来连接的请求。如果srv.Addr是空的话,则使用“:http”。
func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error//ListenAndServeTLS监听srv.Addr确定的TCP地址,并且会调用Serve方法处理接收到的连接。必须提供证书文件和对应的私钥文 件。如果证书是由权威机构签发的,certFile参数必须是顺序串联的服务端证书和CA证书。如果srv.Addr为空字符串,会使 用”:https”。
func (srv *Server) Serve(l net.Listener) error//接受Listener l的连接,创建一个新的服务协程。该服务协程读取请求然后调用srv.Handler来应答。实际上就是实现了对某个端口进行监听,然后创建相应的连接。
func (s *Server) SetKeepAlivesEnabled(v bool)//该函数控制是否http的keep-alives能够使用,默认情况下,keep-alives总是可用的。只有资源非常紧张的环境或者服务端在关闭进程中时,才应该关闭该功能。
举例说明Server的用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package mainimport ( "fmt" "net/http" ) func Test (w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "just for test!" ) } func main () { newserver := http.Server{ Addr: ":9992" , ReadTimeout: 0 , WriteTimeout: 0 , } mux := http.NewServeMux() mux.Handle("/" , http.FileServer(http.Dir("/home" ))) mux.HandleFunc("/test" , Test) newserver.Handler = mux err := newserver.ListenAndServe() if err != nil { fmt.Println(err) } fmt.Println(err) }
type Transport struct type Transport //该结构体实现了RoundTripper接口,支持HTTP,HTTPS以及HTTP代理,TranSport也能缓存连接供将来使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 type Transport struct { Proxy func (*Request) (*url.URL, error) Dial func (network, addr string ) (net.Conn, error) DialTLS func (network, addr string ) (net.Conn, error) TLSClientConfig *tls.Config TLSHandshakeTimeout time.Duration DisableKeepAlives bool DisableCompression bool MaxIdleConnsPerHost int ResponseHeaderTimeout time.Duration }
func (t *Transport) CancelRequest(req *Request)//通过关闭连接来取消传送中的请求。
func (t *Transport) CloseIdleConnections()//关闭所有之前请求但目前处于空闲状态的连接。该方法并不中断任何正在使用的连接。
func (t *Transport) RegisterProtocol(scheme string, rt RoundTripper)//RegisterProtocol注册一个新的名为scheme的协议。t会将使用scheme协议的请求转交给rt。rt有责任模拟HTTP请求的语义。RegisterProtocol可以被其他包用于提供”ftp”或”file”等协议的实现。
func (t *Transport) RoundTrip(req *Request) (resp *Response, err error)//该函数实现了RoundTripper接口,对于高层http客户端支持,例如处理cookies以及重定向,查看Get,Post以及Client类型。
io/ioutil 包函数 Discard Discard 是一个 io.Writer 接口,调用它的 Write 方法将不做任何事情并且始终成功返回。
1 var Discard io.Writer = devNull(0 )
ReadAll ReadAll 读取 r 中的所有数据,返回读取的数据和遇到的错误。 如果读取成功,则 err 返回 nil,而不是 EOF,因为 ReadAll 定义为读取所有数据,所以不会把 EOF 当做错误处理。
1 func ReadAll (r io.Reader) ([]byte , error)
ReadFile ReadFile 读取文件中的所有数据,返回读取的数据和遇到的错误。
如果读取成功,则 err 返回 nil,而不是 EOF。
1 func ReadFile (filename string ) ([]byte , error)
WriteFile WriteFile 向文件中写入数据,写入前会清空文件。
如果文件不存在,则会以指定的权限创建该文件。
返回遇到的错误。
1 func WriteFile (filename string , data []byte , perm os.FileMode) error
ReadDir ReadDir 读取指定目录中的所有目录和文件(不包括子目录)。
返回读取到的文件信息列表和遇到的错误,列表是经过排序的。
1 func ReadDir (dirname string ) ([]os.FileInfo, error)
NopCloser NopCloser 将 r 包装为一个 ReadCloser 类型,但 Close 方法不做任何事情。
1 func NopCloser (r io.Reader) io .ReadCloser
TempFile TempFile 在 dir 目录中创建一个以 prefix 为前缀的临时文件,并将其以读写模式打开。返回创建的文件对象和遇到的错误。
如果 dir 为空,则在默认的临时目录中创建文件(参见 os.TempDir),多次调用会创建不同的临时文件,调用者可以通过 f.Name() 获取文件的完整路径。
调用本函数所创建的临时文件,应该由调用者自己删除。
1 func TempFile (dir, prefix string ) (f *os.File, err error)
TempDir TempDir 功能同 TempFile,只不过创建的是目录,返回目录的完整路径。
1 func TempDir (dir, prefix string ) (name string , err error)
例子 读取目录:
1 2 3 4 5 6 7 8 9 10 11 12 func main () { rd, err := ioutil.ReadDir("/" ) fmt.Println(err) for _, fi := range rd { if fi.IsDir() { fmt.Printf("[%s]\n" , fi.Name()) } else { fmt.Println(fi.Name()) } } }
临时目录、临时文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 func main () { dir, err := ioutil.TempDir("" , "Test" ) if err != nil { fmt.Println(err) } defer os.Remove(dir) fmt.Printf("%s\n" , dir) f, err := ioutil.TempFile(dir, "Test" ) if err != nil { fmt.Println(err) } defer os.Remove(f.Name()) fmt.Printf("%s\n" , f.Name()) }
os 包函数 获取当前目录、改变目录 1 2 3 4 5 6 7 8 9 func Getwd () (dir string , err error) //获取当前目录func Chdir (dir string ) error // 修改当前目录eg. func main () { fmt.Println(os.Getwd()) os.Chdir("/Users/rtk" ) fmt.Println(os.Getwd()) }
修改文件权限 1 2 3 4 5 6 7 8 func Chmod (name string , mode FileMode) error eg. 将文件改为不可读: func main () { fmt.Println(os.Getwd()) os.Chdir("/Users/xujie/Desktop" ) os.Chmod("file.txt" ,0 ) }
获取用户识别码uid 和 群组识别码gid 1 2 3 4 func Getuid () int func Getegid () int // 有效的用户识别码func Geteuid () int // 有效的群组识别码func Getgid () int
查看用户所属组的列表 1 func Getgroups () ([]int , error)
返回底层系统的内存页面大小
获取主机名称 1 func Hostname () (name string , err error)
获取当前进程id、父进程id 1 2 func Getpid () // 获取当前进程id func Getppid () // 获取父进程id
获取文件的状态 1 2 3 4 5 6 7 8 9 10 11 12 func Stat (name string ) (FileInfo, error) eg. func main () { filename := "/Users/xujie/Desktop/file.txt" file,_:=os.Stat(filename) fmt.Println(file.Name()) fmt.Println(file.IsDir()) fmt.Println(file.Size()) fmt.Println(file.Mode()) fmt.Println(file.Sys()) }
错误检测 1 2 3 4 5 6 7 8 9 10 11 func IsExist (err error) bool // 文件存在,但是由系统产生错误func IsNotExist (err error) bool // 目录或者文件不存在时返回true func IsPermission (err error) bool // 检测是不是由于权限不足导致的错误eg. func main () { filename := "file.txt" _, err := os.Stat(filename); fmt.Println(os.IsExist(err)) fmt.Println(os.IsNotExist(err)) }
创建文件夹、删除文件或文件夹 1 2 3 4 func Mkdir (name string , perm FileMode) error func Remove (name string ) error func RemoveAll (name string ) error // 删除文件夹下所有文件
修改文件夹或文件的名称 1 func Rename (oldpath, newpath string ) error
移动文件夹或文件 1 func Rename (oldpath, newpath string ) error
新建文件 1 func Create (name string ) (*File, error)
这个方法创建文件是默认的权限为0666,如果已经存在同名的文件,则调用此方法,会覆盖掉原来的文件
打开文件 1 func Open (name string ) (*File, error)
如果打开的文件不存在,则会返回错误 open file1.txt: no such file or directory
写入文件 1 2 3 func (f *File) Write (b []byte ) (n int , err error) func (f *File) WriteAt (b []byte , off int64 ) (n int , err error) func (f *File) WriteString (s string ) (n int , err error)
要注意的是,os.open() 打开的文件是只读的,写入不成功,需要:
1 2 3 4 5 6 7 8 9 10 11 12 13 func OpenFile (name string , flag int , perm FileMode) (*File, error) 第二个参数 O_RDONLY 打开只读文件 O_WRONLY 打开只写文件 O_RDWR 打开既可以读取又可以写入文件 O_APPEND 写入文件时将数据追加到文件尾部 O_CREATE 如果文件不存在,则创建一个新的文件 O_EXCL 文件必须不存在,然后会创建一个新的文件 O_SYNC 打开同步I/0 O_TRUNC 文件打开时可以截断 第三个参数就是权限模式
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 func main () { os.Chdir("/Users/xujie/Desktop" ) file,error:= os.OpenFile("file.txt" ,os.O_RDWR,0666 ) defer file.Close() if error != nil { fmt.Println(error) } _,error = file.WriteString("你好" ) _,error = file.WriteString("从天有一个书" ) fmt.Println(error) }
读取文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 func main () { os.Chdir("/Users/xujie/Desktop" ) file,error:= os.Open("file.txt" ) defer file.Close() if error != nil { fmt.Println(error) return } fileInfo,_ := file.Stat() fmt.Println(fileInfo.Size()) data := make ([]byte ,fileInfo.Size()) _,error = file.Read(data) fmt.Println(error) fmt.Println(string (data)) }
关闭文件 1 2 3 func (f *File) Close () error defer file.Close()
检测文件是否是同一个 1 func SameFile (fi1, fi2 FileInfo) bool
就算是同一个文件,没在同一个路径下也会返回false,判断依据如下 这意味着两个基础结构的 inode 字段是相同的
获取文件模式相关信息 1 2 3 4 5 6 7 8 9 10 11 12 13 func (m FileMode) IsDir () bool func (m FileMode) IsRegular () bool func (m FileMode) Perm () FileMode func (m FileMode) String () string eg. func main () { fileInfo1,_:= os.Stat("/Users/xujie/Desktop/DataParser.zip" ) fmt.Println(fileInfo1.Mode().String()) fmt.Println(fileInfo1.Mode().IsRegular()) fmt.Println(fileInfo1.Mode().IsDir()) fmt.Println(fileInfo1.Mode().Perm()) }
把文件所在的目录切换为当前目录 1 func (f *File) Chdir () error
查看文件名称 1 func (f *File) Name () string
如何查看所有文件夹下的所有文件和文件数量 1 2 3 4 5 6 7 8 9 10 11 func (f *File) Readdir (n int ) ([]FileInfo, error) eg. func main () { file,_ := os.Open("/Users/xujie/Desktop/未命名文件夹" ) files,_ := file.Readdir(10 ) for _,f := range files { fmt.Println(f.Name()) } }
读取文件夹的下面文件的名称 1 2 3 4 5 6 7 8 9 10 func (f *File) Readdirnames (n int ) (names []string , err error) eg: func main () { file,_ := os.Open("/Users/xujie/Desktop/未命名文件夹" ) fileNames,_ := file.Readdirnames(-1 ) for _,name := range fileNames { fmt.Println(name) } }
获取临时陌路的文件夹路径
判断字符是否是支持的路径分隔符 1 2 3 4 5 6 7 8 func IsPathSeparator (c uint8 ) bool eg: func main () { fmt.Println(os.IsPathSeparator('c' )) fmt.Println(os.IsPathSeparator('\\' )) fmt.Println(os.IsPathSeparator('/' )) }
查看环境变量 1 2 3 4 func Getenv (key string ) string func LookupEnv (key string ) (string , bool )
查找指定环境变量 1 2 3 func func Expand (s string , mapping func (string ) string ) string func ExpandEnv (s string ) string
获取文件对应的unix文件描述符 1 func (f *File) Fd () uintptr
Chown修改文件的用户ID和组ID 1 func Chown (name string , uid, gid int ) error
修改文件权限 1 func (f *File) Chmod (mode FileMode) error
强制改变文件大小 两个方法:
1 2 3 func Truncate (name string , size int64 ) error func (f *File) Truncate (size int64 ) error
减小文件大小会造成内容丢失。
链接 硬链接 硬链接(hard link, 也称链接)就是一个文件的一个或多个文件名。再说白点,所谓链接无非是把文件名和计算机文件系统使用的节点号链接起来。因此我们可以用多个文件名与同一个文件进行链接,这些文件名可以在同一目录或不同目录
1 func Link (oldname, newname string ) error
同步保存当前文件的内容 1 func (f *File) Sync () error
Sync递交文件的当前内容进行稳定的存储。一般来说,这表示将文件系统的最近写入的数据在内存中的拷贝刷新到硬盘中稳定保存
1 2 3 4 5 6 7 8 func main () { file,error := os.OpenFile("/Users/xujie/Desktop/file.txt" ,os.O_RDWR,0777 ) if error != nil { fmt.Println(error) } file.WriteString("新内容" ) file.Sync() }
NewFile使用给出的Unix文件描述符和名称创建一个文件 1 func NewFile (fd uintptr , name string ) *File
Lstat返回一个描述name指定的文件对象的FileInfo 1 func Lstat (name string ) (fi FileInfo, err error)
Lstat返回一个描述name指定的文件对象的FileInfo。如果指定的文件对象是一个符号链接,返回的FileInfo描述该符号链接的信息,本函数不会试图跳转该链接。如果出错,返回的错误值为*PathError类型
查看所有环境变量、清除环境变量 1 2 func Environ () []string func Clearenv () []string //慎用!!
获取当前程序可执行的文件地址 1 func Executable () (string , error)
让程序已给定的状态码退出 Exit让当前程序以给出的状态码code退出。一般来说,状态码0表示成功,非0表示出错。程序会立刻终止,defer的函数不会被执行
设置环和取消环境变量 1 2 3 4 5 6 7 8 9 func Unsetenv (key string ) error func Setenv (key, value string ) error eg: func main () { os.Setenv("TMPDIR" , "/my/tmp" ) defer os.Unsetenv("TMPDIR" ) }
创建软链接 软连接和硬链接的区别
1 func Symlink (oldname, newname string ) error
获取软链接文件对应的实际文件路径地址 1 func Readlink (name string ) (string , error)
更改指定文件的访问和修改时间 1 func Chtimes (name string , atime time.Time, mtime time.Time) error
第二个参数访问时间 第三个参数修改时间
1 os.Chtimes("/Users/xujie/Desktop/file.txt" ,time.Now(),time.Now().Add(time.Hour * 24 ))
创建文件夹,并设置权限 1 func MkdirAll (path string , perm FileMode) error
规则:
如果已经存在同名文件夹,则此方法不做任何事情
文件夹里面所有文件都是同样的权限
设置文章的读写位置 1 func (f *File) Seek (offset int64 , whence int ) (ret int64 , err error)
Seek设置下一次读/写的位置。offset为相对偏移量,而whence决定相对位置:0为相对文件开头,1为相对当前位置,2为相对文件结尾。它返回新的偏移量(相对开头)和可能的错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 eg: func main () { file,error := os.Open("/Users/xujie/Desktop/file.txt" ) defer file.Close() if error != nil { fmt.Println(error) return } offset := int64 (0 ) data := make ([]byte ,10 ) totalData := make ([]byte ,0 ,100 ) for { file.Seek(offset,0 ) offset += 10 _,error = file.Read(data) if error != nil { fmt.Println(error) break } totalData = append (totalData,data...) fmt.Println(string (data)) } fmt.Println(string (totalData)) }
file.Seek(offset,0) offset = 0 从文件中读取10个数据,之后偏移量设置为offset = 10,则从文件内容第11个字节开始读取,当Read方法读取文件到结尾时,会返回EOF标识,这个时候程序退出for循环
修改文件权限 1 func Lchown (name string , uid, gid int ) error
管道的用法 1 func Pipe () (r *File, w *File, err error)
这个方法主要在协程之间进行数据传递,r.read 方法会等待接受w文件中写数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 func main () { r,w,error := os.Pipe() go write(w) data := make ([]byte ,1000 ) n,_ := r.Read(data) if error != nil { println (error) } fmt.Println("读取数据:" ) fmt.Println(string (data[:n])) } func write (w *os.File) { time.AfterFunc(time.Second* 2 , func () { w.WriteString("ABCD" ) w.WriteString("EFGH" ) fmt.Println("数据已写入w" ) }) }
创建系统错误 1 func NewSyscallError (syscall string , err error) error
通过pid查找进行进程 1 func FindProcess (pid int ) (*Process, error)
查找增加运行的进程,但是在 Unix 系统上,无论过程是否存在,FindProcess 都会成功并为给定的 PID 返回一个 Process
杀死进程 1 func (p *Process) Kill () error
1 2 3 4 5 6 7 8 9 10 11 12 func main () { pid := os.Getpid() process,error := os.FindProcess(pid) if error != nil { fmt.Println(error) } process.Kill() fmt.Println(pid) fmt.Println(process) }
释放与进程p关联的任何资源 1 func (p *Process) Release () error
Release释放进程p绑定的所有资源, 使它们(资源)不能再被(进程p)使用。只有没有调用Wait方法时才需要调用本方法
1 2 3 4 5 6 7 8 9 10 11 func (p *Process) Signal (sig Signal) error func (p Process) Wait () (ProcessState, error) func (p *ProcessState) Exited () bool func (p *ProcessState) Pid () int func (p *ProcessState) String () string func (p *ProcessState) Success () bool func (p *ProcessState) Sys () interface {}func (p *ProcessState) SysUsage () interface {}func (p *ProcessState) SystemTime () time .Duration func (p *ProcessState) UserTime () time .Duration func (e *SyscallError) Error () string
runtime 包runtime 包 提供了运行时与系统的交互,比如控制协程函数,触发垃圾立即回收等等底层操作
函数 获取GO的信息 1 2 3 4 5 6 func GOROOT () string // 获取GOROOT 环境变量func Version () string // 获取GO 的版本号func NumCPU () int // 获取本机逻辑CPU 个数func GOMAXPROCS (n int ) int // 设置最大可同时执行的最大CPU 数
设置cpu profile记录的速率 1 func SetCPUProfileRate (hz int )
SetCPUProfileRate设置CPU profile记录的速率为平均每秒hz次。如果hz<=0,SetCPUProfileRate会关闭profile的记录。如果记录器在执行,该速率必须在关闭之后才能修改。
绝大多数使用者应使用runtime/pprof包或testing包的-test.cpuprofile选项而非直接使用SetCPUProfileRate
立即执行一次垃圾回收
给变量绑定方法,当垃圾回收的时候进行监听 1 func SetFinalizer (x, f interface {})
注意x必须是指针类型,f 函数的参数一定要和x保持一致,或者写interface{},不然程序会报错
1 2 3 4 5 6 7 8 9 10 11 type Student struct { name string } func main () { var i *Student = new (Student) runtime.SetFinalizer(i, func (i *Student) { println ("垃圾回收了" ) }) runtime.GC() time.Sleep(time.Second) }
查看内存申请和分配统计信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 func ReadMemStats (m *MemStats) type MemStats struct { Alloc uint64 TotalAlloc uint64 Sys uint64 Lookups uint64 Mallocs uint64 Frees uint64 HeapAlloc uint64 HeapSys uint64 HeapIdle uint64 HeapInuse uint64 HeapReleased uint64 HeapObjects uint64 StackInuse uint64 StackSys uint64 MSpanInuse uint64 MSpanSys uint64 MCacheInuse uint64 MCacheSys uint64 BuckHashSys uint64 GCSys uint64 OtherSys uint64 NextGC uint64 LastGC uint64 PauseTotalNs uint64 PauseNs [256 ]uint64 NumGC uint32 EnableGC bool DebugGC bool BySize [61 ]struct { Size uint32 Mallocs uint64 Frees uint64 } }
查看程序 1 2 3 4 5 func (r *MemProfileRecord) InUseBytes () int64 // InUseBytes 返回正在使用的字节数(AllocBytes – FreeBytes )func (r *MemProfileRecord) InUseObjects () int64 //InUseObjects 返回正在使用的对象数(AllocObjects - FreeObjects )func (r *MemProfileRecord) Stack () []uintptr // Stack 返回关联至此记录的调用栈踪迹,即r .Stack0 的前缀。func MemProfile (p []MemProfileRecord, inuseZero bool ) (n int , ok bool )
MemProfile返回当前内存profile中的记录数n。若len(p)>=n,MemProfile会将此分析报告复制到p中并返回(n, true);如果len(p)< n,MemProfile则不会更改p,而只返回(n, false)。
如果inuseZero为真,该profile就会包含无效分配记录(其中r.AllocBytes>0,而r.AllocBytes==r.FreeBytes。这些内存都是被申请后又释放回运行时环境的)。
大多数调用者应当使用runtime/pprof包或testing包的-test.memprofile标记,而非直接调用MemProfile
执行一个断点 1 2 func Breakpoint () runtime.Breakpoint()
获取程序调用go协程的栈踪迹历史 1 func Stack (buf []byte , all bool ) int
Stack将调用其的go程的调用栈踪迹格式化后写入到buf中并返回写入的字节数。若all为true,函数会在写入当前go程的踪迹信息后,将其它所有go程的调用栈踪迹都格式化写入到buf中。
获取当前函数或者上层函数的标识号、文件名、调用方法在当前文件中的行号 1 2 3 4 5 6 7 8 9 10 func Caller (skip int ) (pc uintptr , file string , line int , ok bool ) eg: func main () { pc,file,line,ok := runtime.Caller(0 ) fmt.Println(pc) fmt.Println(file) fmt.Println(line) fmt.Println(ok) }
获取与当前堆栈记录相关链的调用栈踪迹 1 func Callers (skip int , pc []uintptr ) int
函数把当前go程调用栈上的调用栈标识符填入切片pc中,返回写入到pc中的项数。实参skip为开始在pc中记录之前所要跳过的栈帧数,0表示Callers自身的调用栈,1表示Callers所在的调用栈。返回写入p的项数。
获取一个标识调用栈标识符pc对应的调用栈 1 func FuncForPC (pc uintptr ) *Func
1 2 3 4 func (f *Func) Name () string // 获取调用栈所调用的函数的名字func (f *Func) FileLine (pc uintptr ) (file string , line int ) func (f *Func) Entry () uintptr // 获取该调用栈的调用栈标识符
获取当前进程执行的cgo调用次数
获取当前存在的go协程数
终止掉当前的go协程
Goexit终止调用它的go协程,其他协程不受影响,Goexit会在终止该go协程前执行所有的defer函数,前提是defer必须在它前面定义,如果在main go协程调用本方法,会终止该go协程,但不会让main返回,因为main函数没有返回,程序会继续执行其他go协程,当其他go协程执行完毕后,程序就会崩溃.
让其他go协程优先执行,等其他协程执行完后,在执行当前的协程
获取活跃的go协程的堆栈profile以及记录个数 1 func GoroutineProfile (p []StackRecord) (n int , ok bool )
将调用的go协程绑定到当前所在的操作系统线程,其它go协程不能进入该线程
将调用的go程绑定到它当前所在的操作系统线程。除非调用的go程退出或调用UnlockOSThread,否则它将总是在该线程中执行,而其它go程则不能进入该线程
将调用的go程解除和它绑定的操作系统线程。若调用的go程未调用LockOSThread,UnlockOSThread不做操作
获取线程创建profile中的记录个数 1 func ThreadCreateProfile (p []StackRecord) (n int , ok bool )
返回线程创建profile中的记录个数。如果len(p)>=n,本函数就会将profile中的记录复制到p中并返回(n, true)。若len(p)< n,则不会更改p,而只返回(n, false)。
绝大多数使用者应当使用runtime/pprof包,而非直接调用ThreadCreateProfile。
控制阻塞profile记录go协程阻塞事件的采样率 1 func SetBlockProfileRate (rate int )
SetBlockProfileRate控制阻塞profile记录go程阻塞事件的采样频率。对于一个阻塞事件,平均每阻塞rate纳秒,阻塞profile记录器就采集一份样本。
要在profile中包括每一个阻塞事件,需传入rate=1;要完全关闭阻塞profile的记录,需传入rate<=0。
返回当前阻塞profile中的记录个数 1 func BlockProfile (p []BlockProfileRecord) (n int , ok bool )
BlockProfile返回当前阻塞profile中的记录个数。如果len(p)>=n,本函数就会将此profile中的记录复制到p中并返回(n, true)。如果len(p)< ,本函数则不会修改p,而只返回(n, false)。
绝大多数使用者应当使用runtime/pprof包或testing包的-test.blockprofile标记, 而非直接调用 BlockProfile。
sort 包sort包中实现了3种基本的排序算法:插入排序.快排和堆排序.和其他语言中一样,这三种方式都是不公开的,他们只在sort包内部使用.所以用户在使用sort包进行排序时无需考虑使用那种排序方式,sort.Interface定义的三个方法:获取数据集合长度的Len()方法、比较两个元素大小的Less()方法和交换两个元素位置的Swap()方法,就可以顺利对数据集合进行排序。sort包会根据实际数据自动选择高效的排序算法。
type Interface 1 2 3 4 5 6 7 8 type Interface interface { Len() int Less(i, j int ) bool Swap(i, j int ) }
任何实现了 sort.Interface 的类型(一般为集合),均可使用该包中的方法进行排序。这些方法要求集合内列出元素的索引为整数。
golang自身实现的interface有三种,Float64Slice,IntSlice,StringSlice
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package main import ( "fmt" "sort" ) type IntSlice []int func (c IntSlice) Len () int { return len (c) } func (c IntSlice) Swap (i, j int ) { c[i], c[j] = c[j], c[i] } func (c IntSlice) Less (i, j int ) bool { return c[i] < c[j] } func main () { a := IntSlice{1 , 3 , 5 , 7 , 2 } b := []float64 {1.1 , 2.3 , 5.3 , 3.4 } c := []int {1 , 3 , 5 , 4 , 2 } fmt.Println(sort.IsSorted(a)) if !sort.IsSorted(a) { sort.Sort(a) } if !sort.Float64sAreSorted(b) { sort.Float64s(b) } if !sort.IntsAreSorted(c) { sort.Ints(c) } fmt.Println(a) fmt.Println(b) fmt.Println(c) }
Search 二分法查找 func Search(n int, f func(int) bool) int
使用二分法查找(常用于一个已排序、可索引的数据结构,如数组、切片),查找范围是[0:n],返回能使f(i)=true的最小i(0 <= i < n),并且会假定,如果f(i)=true,则f(i+1)=true,即对于切片[0:n],i之前的切片元素会使f()函数返回false,i及i之后的元素会使f()函数返回true。但是,当在切片中无法找到时f(i)=true的i时(此时切片元素都不能使f()函数返回true),Search()方法会返回n(而不是返回-1)。
为了查找某个值,而不是某一范围的值时,如果slice以升序排序,则 f func中应该使用>=,如果slice以降序排序,则应该使用<=。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package main import ( "fmt" "sort" ) func main () { a := []int {1 , 2 , 3 , 4 , 5 } b := sort.Search(len (a), func (i int ) bool { return a[i] >= 30 }) fmt.Println(b) c := sort.Search(len (a), func (i int ) bool { return a[i] <= 3 }) fmt.Println(c) d := sort.Search(len (a), func (i int ) bool { return a[i] == 3 }) fmt.Println(d) }
1 2 3 4 5 6 func SearchFloat64s (a []float64 , x float64 ) int func SearchInts (a []int , x int ) int func SearchStrings (a []string , x string ) int
其中需要注意的是,以上三种search查找方法,其对应的slice必须按照升序 进行排序,否则会出现奇怪的结果.
Stable 排序 func Stable(data Interface) :Stable对data进行排序,不过排序过程中,如果data中存在相等的元素,则他们原来的顺序不会改变,即如果有两个相等元素num,他们的初始index分别为i和j,并且i < j,则利用Stable对data进行排序后,i依然小于j.直接利用sort进行排序则不能够保证这一点.
Reverse 逆序排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 func Reverse (data Interface) Interface package main import ( "fmt" "sort" ) func main () { a := []int {1 , 2 , 5 , 3 , 4 } fmt.Println(a) sort.Sort(sort.Reverse(sort.IntSlice(a))) fmt.Println(a) }
strconv 包与字符串相关的类型转换。 包含了一些变量用于获取程序运行的操作系统平台下 int 类型所占的位数,如:strconv.IntSize。 任何类型 T 转换为字符串总是成功的。 数字 → 字符串:
strconv.Itoa(i int) string 返回数字 i 所表示的字符串类型的十进制数。
strconv.FormatFloat(f float64, fmt byte, prec int, bitSize int) string 将64位浮点型数字转换为字符串,其中 fmt 表示格式(其值可以是 b、e、f 或 g),prec 表示精度,bitSize 则使用 32 表示 float32,用 64 表示 float64。
将字符串转换为其他类型 tp 并不总是可能的,可能会在运行时抛出错误 parsing "…": invalid argument。 字符串 → 数字类型:
strconv.Atoi(s string) (i int, err error) 将字符串转换为 int 型。
strconv.ParseFloat(s string, bitSize int) (f float64, err error) 将字符串转换为 float64 型。
利用多个返回值的特性(第 1 个是转换后的结果(若成功),第 2 个是可能出现的错误),一般使用如下形式进行从字符串到其它类型的转换:
1 val, err = strconv.Atoi(s)
strings 包Go 中使用 strings 包对字符串进行操作。中文文档 、 官方文档 或 国内访问文档
前、后缀 HasPrefix 判断字符串 s 是否以 prefix 开头:
1 strings.HasPrefix(s, prefix string ) bool
HasSuffix 判断字符串 s 是否以 suffix 结尾:
1 strings.HasSuffix(s, suffix string ) bool
字符串包含关系 Contains 判断字符串 s 是否包含 substr :
1 strings.Contains(s, substr string ) bool
func ContainsAny(s, chars string) bool : 判断字符串s是否包含chars中任意一个字符,若chars为空,返回false
func ContainsRune(s string, r rune) bool : 是否包含r rune
索引字符串位置 Index 返回字符串 str 在字符串 s 中的第一次出现的索引(str 的第一个字符的索引), 返回 -1 表示 s 不包含 str:
1 strings.Index(s, str string ) int
LastIndex 返回 str 在 s 中最后出现的所有(第一个字符), 返回 -1 表示 s 不包含 str:
1 strings.LastIndex(s, str string ) int
建议用 IndexRune 查询非 ASCII 编码的字符在字符串中的位置(返回 -1 表示 s 不包含 str: ):
1 2 3 4 5 strings.IndexRune(s string , r rune ) int strings.IndexRune("chicken" , 99 ) strings.IndexRune("chicken" , rune ('k' ))
字符串替换 Replace 用于将字符串 str 中的前 n 个字符串 old 替换为字符串 new,并范围一个新的字符串,如果 n = -1 啧替换所有有 old 为 new:
1 strings.Replace(str, old, new , n) string
返回的是str的副本
统计字符串出现的次数 Count 用于统计字符串 str 中字符串 s 出现的非重叠次数:
1 strings.Count(s, str string ) int
重复字符串 Repeat 用于重复 count 次字符串 s 并返回一个新的字符串:
1 strings.Repeat(s, count int ) string
修改字符串大小写 ToLower 将字符串中的 Unicode 字符全部转换为相应的小写字符:
1 strings.Tolower(s) string
ToUpper 将字符串中的 Unicode 字符全部转换为相应的大写字符:
1 strings.ToUpper(s) string
ToTitle s 中的所有字符修改为其 Title 格式:
1 func ToTitle (s string ) string
修剪字符串 strings.TrimSpace(s) 用于剔除字符串开头和结尾的空白符号;strings.Trim(s, "cut") 用于剔除字符串开头和结尾的 cut;TrimLeft 或者 TrimRight 用于只剔除开头或结尾的字符串。
1 2 3 func TrimSpace (s string ) string func Trim (s string , cutset string ) string func TrimRight (s string , cutset string ) string
注:TrimSuffix只是去掉s字符串结尾的suffix字符串,只是去掉1次,而TrimRight是一直去掉s字符串右边的字符串,只要有响应的字符串就去掉,是一个多次的过程,这也是二者的本质区别.
分割字符串 strings.Fields(s) 会利用 1 个或多个空白符号(\t, \n, \v, \f, \r, ‘ ‘, U+0085 (NEL), U+00A0 (NBSP))来作为动态长度的分隔符将字符串分割成若干小块,并返回一个 slice,如果字符串只包含空白符号,则返回一个长度为 0 的空 slice。
strings.Split(s, sep) 用于自定义分割符号来对指定字符串进行分割,同样范围 slice。 因为这 2 个函数都会返回 slice,所以习惯使用 for - range 循环来对其进行处理。
拼接 slice 到字符串 Join 用于将元素类型为 string 的 slice 使用分割符号来拼接组成一个字符串:
1 strings.Join(sl [string ], sep string ) string
从字符串中读取内容 strings.NewReader(str) 用于生成一个 ‘Reader’ 并读取字符串中的内容,然后返回指向该 Reader 的指针,从其他类型读取内容的函数还有:Read 从 []byte 中读取内容;ReadByte() 和 ReadRune() 从字符串中读取下一个 byte 或者 rune。
比较两字符串字典顺序 func Compare(a, b string) int return 0 if a==b, -1 if a < b, and +1 if a > b. 但不常用,通常用 go 自身的 ==, >, < 来比较,更快更易懂。
忽略大小写判断s和t是否相等 func EqualFold(s, t string) bool
Map func Map(mapping func(rune) rune, s string) string :s 中满足 mapping(rune) 的字符替换为 mapping(rune) 的返回值。如果 mapping(rune) 返回负数,则相应的字符将被删除。
1 2 3 4 5 6 7 8 9 10 11 12 func Slash (r rune ) rune { if r == '\\' { return '/' } return r } func main () { s := "C:\\Windows\\System32\\FileName" ms := strings.Map(Slash, s) fmt.Printf("%q\n" , ms) }
reader.go Reader结构 1 2 3 4 5 6 7 8 9 10 11 12 type Reader struct { s string i int prevRune int } func NewReader (s string ) *Reader { return &Reader{s, 0 , -1 } }
Len 返回 r.i 之后的所有数据的字节长度 1 func (r *Reader) Len () int
Read 将 r.i 之后的所有数据写入到 b 中(如果 b 的容量足够大) 返回读取的字节数和读取过程中遇到的错误 如果无可读数据,则返回 io.EOF
1 2 3 4 5 6 7 8 9 10 11 12 13 func (r *Reader) Read (b []byte ) (n int , err error) func main () { s := "Hello World!" r := strings.NewReader(s) b := make ([]byte , 5 ) for n, _ := r.Read(b); n > 0 ; n, _ = r.Read(b) { fmt.Printf("%q, " , b[:n]) } }
ReadAt 将 off 之后的所有数据写入到 b 中(如果 b 的容量足够大) 返回读取的字节数和读取过程中遇到的错误 如果无可读数据,则返回 io.EOF 如果数据被一次性读取完毕,则返回 io.EOF
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 func (r *Reader) ReadAt (b []byte , off int64 ) (n int , err error) func main () { s := "Hello World!" r := strings.NewReader(s) b := make ([]byte , 5 ) n, _ := r.ReadAt(b, 0 ) fmt.Printf("%q\n" , b[:n]) n, _ = r.ReadAt(b, 6 ) fmt.Printf("%q\n" , b[:n]) }
ReadByte 将 r.i 之后的一个字节写入到返回值 b 中 返回读取的字节和读取过程中遇到的错误 如果无可读数据,则返回 io.EOF
1 2 3 4 5 6 7 8 9 10 11 12 func (r *Reader) ReadByte () (b byte , err error) func main () { s := "Hello World!" r := strings.NewReader(s) for i := 0 ; i < 3 ; i++ { b, _ := r.ReadByte() fmt.Printf("%q, " , b) } }
UnreadByte 撤消前一次的 ReadByte 操作,即 r.i– 1 2 3 4 5 6 7 8 9 10 11 12 13 func (r *Reader) UnreadByte () error func main () { s := "Hello World!" r := strings.NewReader(s) for i := 0 ; i < 3 ; i++ { b, _ := r.ReadByte() fmt.Printf("%q, " , b) r.UnreadByte() } }
ReadRune 将 r.i 之后的一个字符写入到返回值 ch 中 ch: 读取的字符 size:ch 的编码长度 err: 读取过程中遇到的错误 如果无可读数据,则返回 io.EOF 如果 r.i 之后不是一个合法的 UTF-8 字符编码,则返回 utf8.RuneError 字符
1 2 3 4 5 6 7 8 9 10 11 12 13 func (r *Reader) ReadRune () (ch rune , size int , err error) func main () { s := "你好 世界!" r := strings.NewReader(s) for i := 0 ; i < 5 ; i++ { b, n, _ := r.ReadRune() fmt.Printf(`"%c:%v", ` , b, n) } }
撤消前一次的 ReadRune 操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 func (r *Reader) UnreadRune () error func main () { s := "你好 世界!" r := strings.NewReader(s) for i := 0 ; i < 5 ; i++ { b, _, _ := r.ReadRune() fmt.Printf("%q, " , b) r.UnreadRune() } }
Seek 用来移动 r 中的索引位置 offset:要移动的偏移量,负数表示反向移动 whence:从那里开始移动,0:起始位置,1:当前位置,2:结尾位置 如果 whence 不是 0、1、2,则返回错误信息 如果目标索引位置超出字符串范围,则返回错误信息 目标索引位置不能超出 1 << 31,否则返回错误信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 func (r *Reader) Seek (offset int64 , whence int ) (int64 , error) func main () { s := "Hello World!" r := strings.NewReader(s) b := make ([]byte , 5 ) r.Seek(6 , 0 ) r.Read(b) fmt.Printf("%q\n" , b) r.Seek(-5 , 1 ) r.Read(b) fmt.Printf("%q\n" , b) }
WriteTo 将 r.i 之后的数据写入接口 w 中 1 2 3 4 5 6 7 8 9 10 11 12 func (r *Reader) WriteTo (w io.Writer) (n int64 , err error) func main () { s := "Hello World!" r := strings.NewReader(s) buf := bytes.NewBuffer(nil ) r.WriteTo(buf) fmt.Printf("%q\n" , buf) }
replace.go Replacer 根据一个替换列表执行替换操作 1 2 3 4 type Replacer struct { Replace(s string ) string WriteString(w io.Writer, s string ) (n int , err error) }
NewReplacer 通过“替换列表”创建一个 Replacer 对象 按照“替换列表”中的顺序进行替换,只替换非重叠部分。 如果参数的个数不是偶数,则抛出异常。 如果在“替换列表”中有相同的“查找项”,则后面重复的“查找项”会被忽略
1 func NewReplacer (oldnew ...string ) *Replacer
Replace 返回对 s 进行“查找和替换”后的结果 Replace 使用的是 Boyer-Moore 算法,速度很快
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 func (r *Replacer) Replace (s string ) string func main () { srp := strings.NewReplacer("Hello" , "你好" , "World" , "世界" , "!" , "!" ) s := "Hello World!Hello World!hello world!" rst := srp.Replace(s) fmt.Print(rst) } func main () { wl := []string {"Hello" , "Hi" , "Hello" , "你好" } srp := strings.NewReplacer(wl...) s := "Hello World! Hello World! hello world!" rst := srp.Replace(s) fmt.Print(rst)
WriteString 对 s 进行“查找和替换”,然后将结果写入 w 中 1 2 3 4 5 6 7 8 func (r *Replacer) WriteString (w io.Writer, s string ) (n int , err error) func main () { wl := []string {"Hello" , "你好" , "World" , "世界" , "!" , "!" } srp := strings.NewReplacer(wl...) s := "Hello World!Hello World!hello world!" srp.WriteString(os.Stdout, s)
sync 包临时对象池 Pool 用于存储临时对象,它将使用完毕的对象存入对象池中,在需要的时候取出来重复使用,目的是为了避免重复创建相同的对象造成 GC 负担过重。其中存放的临时对象随时可能被 GC 回收掉(如果该对象不再被其它变量引用)。
从 Pool 中取出对象时,如果 Pool 中没有对象,将返回 nil,但是如果给 Pool.New 字段指定了一个函数的话,Pool 将使用该函数创建一个新对象返回。
Pool 可以安全的在多个例程中并行使用,但 Pool 并不适用于所有空闲对象,Pool 应该用来管理并发的例程共享的临时对象,而不应该管理短寿命对象中的临时对象,因为这种情况下内存不能很好的分配,这些短寿命对象应该自己实现空闲列表。
Pool 在开始使用之后,不能再被复制。
1 2 3 4 5 6 7 8 9 10 type Pool struct { New func () interface {} } func (p *Pool) Put (x interface {}) func (p *Pool) Get () interface {}
Once Once 的作用是多次调用但只执行一次,Once 只有一个方法,Once.Do(),向 Do 传入一个函数,这个函数在第一次执行 Once.Do() 的时候会被调用,以后再执行 Once.Do() 将没有任何动作,即使传入了其它的函数,也不会被执行,如果要执行其它函数,需要重新创建一个 Once 对象。
Once 可以安全的在多个例程中并行使用。
多次调用仅执行一次指定的函数 f:
1 func (o *Once) Do (f func () )
eg:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 func main () { var once sync.Once onceBody := func () { fmt.Println("Only once" ) } done := make (chan bool ) for i := 0 ; i < 10 ; i++ { go func () { once.Do(onceBody) done <- true }() } for i := 0 ; i < 10 ; i++ { <-done } }
互斥锁 互斥锁用来保证在任一时刻,只能有一个例程访问某对象。Mutex 的初始值为解锁状态。Mutex 通常作为其它结构体的匿名字段使用,使该结构体具有 Lock 和 Unlock 方法。
Mutex 可以安全的在多个例程中并行使用。
1 2 3 4 5 6 7 8 9 10 11 type Locker interface { Lock() Unlock() } func (m *Mutex) Lock () func (m *Mutex) Unlock ()
eg:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 type SafeInt struct { sync.Mutex Num int } func main () { count := SafeInt{} done := make (chan bool ) for i := 0 ; i < 10 ; i++ { go func (i int ) { count.Lock() count.Num += i fmt.Print(count.Num, " " ) count.Unlock() done <- true }(i) } for i := 0 ; i < 10 ; i++ { <-done } }
读写互斥锁 RWMutex 比 Mutex 多了一个“读锁定”和“读解锁”,可以让多个例程同时读取某对象。RWMutex 的初始值为解锁状态。RWMutex 通常作为其它结构体的匿名字段使用。
Mutex 可以安全的在多个例程中并行使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 func (rw *RWMutex) Lock () func (rw *RWMutex) Unlock () func (rw *RWMutex) RLock () func (rw *RWMutex) RUnlock () func (rw *RWMutex) RLocker () Locker
组等待 WaitGroup 用于等待一组例程的结束。主例程在创建每个子例程的时候先调用 Add 增加等待计数,每个子例程在结束时调用 Done 减少例程计数。之后,主例程通过 Wait 方法开始等待,直到计数器归零才继续执行。
1 2 3 4 5 6 7 8 func (wg *WaitGroup) Add (delta int ) func (wg *WaitGroup) Done () func (wg *WaitGroup) Wait ()
eg:
1 2 3 4 5 6 7 8 9 10 11 12 13 func main () { wg := sync.WaitGroup{} wg.Add(10 ) for i := 0 ; i < 10 ; i++ { go func (i int ) { defer wg.Done() fmt.Print(i, " " ) }(i) } wg.Wait() }
条件等待 条件等待通过 Wait 让例程等待,通过 Signal 让一个等待的例程继续,通过 Broadcast 让所有等待的例程继续。
在 Wait 之前应当手动为 c.L 上锁,Wait 结束后手动解锁。为避免虚假唤醒,需要将 Wait 放到一个条件判断循环中。官方要求的写法如下:
1 2 3 4 5 6 c.L.Lock() for !condition() { c.Wait() } c.L.Unlock()
Cond 在开始使用之后,不能再被复制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 type Cond struct { L Locker } func NewCond (l Locker) *Cond func (c *Cond) Broadcast () func (c *Cond) Signal () func (c *Cond) Wait ()
eg:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 func main () { condition := false var mu sync.Mutex cond := sync.NewCond(&mu) go func () { mu.Lock() condition = true cond.Signal() mu.Unlock() }() mu.Lock() for !condition { cond.Wait() } fmt.Println("条件满足,开始后续动作..." ) mu.Unlock() }
time 包:时间和日期包中包括了两类时间:时间点(某一时刻)和时长(某一个时间段)time 包提供了一个数据类型 time.Time(作为值使用)以及显示和测量时间和日期的功能函数。
戳→中文文档 、 官方文档 、 国内访问页面
获取当前时间:time.Now();
1 2 3 var t time.Time = time.Now()t := time.Now()
获取时间的一部分: t.Day、t.Minute()… 自定义时间格式化字符串:eg.fmt.Printf("%02d.%02d.%4d\n", t.Day(), t.Month(), t.Year()) 将会输出 08.03.2019 Duration 类型表示两个连续时刻所相差的纳秒数 ,类型为 int64。Location 类型映射某个时区的时间,UTC 表示通用协调世界时间。 包中的一个预定义函数 func (t Time) Format(layout string) string 可以根据一个格式化字符串来将一个t转换为相应格式的字符串,你可以使用一些预定义的格式,如:time.ANSIC 或 time.RFC822。
1 fmt.Println((t.Format("02 Jan 2006 15:04" )))
如果需要在应用程序在经过一定时间或周期执行某项任务(事件处理的特例),则可以使用 time.After 或者 time.Ticker。 另外,time.Sleep(Duration d) 可以实现对某个进程(实质上是 goroutine)时长为 d 的暂停。
时间敞亮(时间格式化) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const ( ANSIC = "Mon Jan _2 15:04:05 2006" UnixDate = "Mon Jan _2 15:04:05 MST 2006" RubyDate = "Mon Jan 02 15:04:05 -0700 2006" RFC822 = "02 Jan 06 15:04 MST" RFC822Z = "02 Jan 06 15:04 -0700" RFC850 = "Monday, 02-Jan-06 15:04:05 MST" RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST" RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" RFC3339 = "2006-01-02T15:04:05Z07:00" RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00" Kitchen = "3:04PM" Stamp = "Jan _2 15:04:05" StampMilli = "Jan _2 15:04:05.000" StampMicro = "Jan _2 15:04:05.000000" StampNano = "Jan _2 15:04:05.000000000" )
这些常量是在time包中进行time 格式化 和time解析而预定义的一些常量,其实他们使用的都是一个特定的时间:Mon Jan 2 15:04:05 MST 2006
函数 time 组成 time.Duration 时间长度,消耗时间time.Time 时间点time.C 放时间的通道(tine.C := make(chan time.Time))
After 函数 1 func After (d Duration) <-chan Time
表示多少时间之后,但是在去除channel内容之前不阻塞,后续程序可以继续执行。
表示休眠多少时间,休眠时处于阻塞状态,后续程序无法执行。
鉴于After特性,其通常用来处理程序超时问题,如下所示:
1 2 3 4 5 6 select {case m := <-c: handle(m) case <-time.After(5 * time.Minute): fmt.Println("timed out" ) }
1 func Tick (d Duration) <-chan Time
time.Tick(time.Duration)用法和time.After差不多,但是它是表示每隔多少时间之后,是一个重复的过程,其他与After一致。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 type Duration int64 func ParseDuration (s string ) (Duration, error) func Since (t Time) Duration func (d Duration) Hours () float64 func (d Duration) Minutes () float64 func (d Duration) Nanoseconds () int64 func (d Duration) Seconds () float64 func (d Duration) String () string
1 2 3 4 type Locationfunc FixedZone (name string , offset int ) *Location func LoadLocation (name string ) (*Location, error) func (l *Location) String () string
1 2 3 type Month func (m Month) String () string //将时间月份以字符串形式打印出来.如fmt .Println (time.June.String() )则打印出June
1 2 type ParseErrorfunc (e *ParseError) Error () string
1 2 3 4 5 6 7 8 9 10 type Ticker func NewTicker (d Duration) *Ticker func (t *Ticker) Stop ()
例子: 使用时间控制停止ticker:
1 2 3 4 5 6 7 8 9 10 11 ticker := time.NewTicker(time.Millisecond * 500 ) go func () { for t := range ticker.C { fmt.Println("Tick at" , t) } }() time.Sleep(time.Millisecond * 1500 ) ticker.Stop() fmt.Println("Ticker stopped" )
使用channel控制停止ticker:
1 2 3 4 5 6 7 8 9 10 11 ticker := time.NewTicker(time.Millisecond * 500 ) c := make (chan int ,num) go func () { for t := range ticker.C { c<-1 fmt.Println("Tick at" , t) } }() ticker.Stop()
这种情况下,在执行num次以Ticker时间为单位的函数之后,c channel中已满,以后便不会再执行对应的函数
1 2 3 4 5 6 7 8 9 10 type Time func Date (year int , month Month, day, hour, min, sec, nsec int , loc *Location) Time t := time.Date(2009 , time.November, 10 , 23 , 0 , 0 , 0 , time.UTC) fmt.Printf("Go launched at %s\n" , t.Local()) Go launched at 2009 -11 -10 15 :00 :00 -0800 PST
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 func Now () Time //返回当前时间,包括日期,时间和时区func Parse (layout, value string ) (Time, error) //输入格式化layout 和时间字符串,输出时间func ParseInLocation (layout, value string , loc *Location) (Time, error) func Unix (sec int64 , nsec int64 ) Time //返回本地时间func (t Time) Add (d Duration) Time //增加时间func (t Time) AddDate (years int , months int , days int ) Time //增加日期func (t Time) After (u Time) bool //判断时间t 是否在时间u的后面func (t Time) Before (u Time) bool //判断时间t 是否在时间u的前面func (t Time) Clock () (hour, min, sec int ) //获取时间t的hour ,min 和second func (t Time) Date () (year int , month Month, day int ) //获取时间t的year ,month 和day func (t Time) Day () int //获取时间t的day func (t Time) Equal (u Time) bool //判断时间t 和时间u 是否相同func (t Time) Format (layout string ) string //时间字符串格式化func (t *Time) GobDecode (data []byte ) error //编码为god func (t Time) GobEncode () ([]byte , error) //解码god func (t Time) Hour () int //获取时间t的小时func (t Time) ISOWeek () (year, week int ) //获取时间t的年份和星期func (t Time) In (loc *Location) Time //获取loc 时区的时间t的对应时间func (t Time) IsZero () bool //判断是否为0时间实例January 1, year 1, 00:00:00 UTC func (t Time) Local () Time //获取当地时间func (t Time) Location () *Location //获取当地时区func (t Time) MarshalBinary () ([]byte , error) //marshal binary 序列化,将时间t 序列化后存入[]byte 数组中func (t Time) MarshalJSON () ([]byte , error) //marshal json 序列化,将时间t 序列化后存入[]byte 数组中func (t Time) MarshalText () ([]byte , error) //marshal text 序列化,将时间t 序列化后存入[]byte 数组中
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 t := time.Date(0 , 0 , 0 , 12 , 15 , 30 , 918273645 , time.UTC) round := []time.Duration{ time.Nanosecond, time.Microsecond, time.Millisecond, time.Second, 2 * time.Second, time.Minute, 10 * time.Minute, time.Hour, } for _, d := range round { fmt.Printf("t.Round(%6s) = %s\n" , d, t.Round(d).Format("15:04:05.999999999" )) }
1 2 3 4 5 6 7 8 9 func (t Time) Second () int //获取时间t的秒func (t Time) String () string //获取时间t的字符串表示func (t Time) Sub (u Time) Duration //与Add 相反,Sub 表示从时间t中减去时间ufunc (t Time) Truncate (d Duration) Time //去尾法求近似值
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 t, _ := time.Parse("2006 Jan 02 15:04:05" , "2012 Dec 07 12:15:30.918273645" ) trunc := []time.Duration{ time.Nanosecond, time.Microsecond, time.Millisecond, time.Second, 2 * time.Second, time.Minute, 10 * time.Minute, time.Hour, } for _, d := range trunc { fmt.Printf("t.Truncate(%6s) = %s\n" , d, t.Truncate(d).Format("15:04:05.999999999" )) } 输出: t.Truncate( 1 ns) = 12 :15 :30.918273645 t.Truncate( 1 µs) = 12 :15 :30.918273 t.Truncate( 1 ms) = 12 :15 :30.918 t.Truncate( 1 s) = 12 :15 :30 t.Truncate( 2 s) = 12 :15 :30 t.Truncate( 1 m0s) = 12 :15 :00 t.Truncate( 10 m0s) = 12 :10 :00 t.Truncate(1 h0m0s) = 12 :00 :00
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 func (t Time) UTC () Time //将本地时间变换为UTC 时区的时间并返回func (t Time) Unix () int64 //返回Unix 时间,该时间是从January 1, 1970 UTC 这个时间开始算起的.func (t Time) UnixNano () int64 //以纳秒为单位返回Unix 时间func (t *Time) UnmarshalBinary (data []byte ) error //将data 数据反序列化到时间t中func (t *Time) UnmarshalJSON (data []byte ) (err error) //将data 数据反序列化到时间t中func (t *Time) UnmarshalText (data []byte ) (err error) //将data 数据反序列化到时间t中func (t Time) Weekday () Weekday //获取时间t的Weekday func (t Time) Year () int //获取时间t的Year func (t Time) YearDay () int //获取时间t的YearDay ,即1年中的第几天func (t Time) Zone () (name string , offset int )
1 2 3 4 5 6 7 8 9 10 11 12 13 type Timer func AfterFunc (d Duration, f func () ) *Timer //和After 差不多,意思是多少时间之后执行函数f func NewTimer (d Duration) *Timer //使用NewTimer () ,可以返回的Timer 类型在计时器到期之前,取消该计时器func (t *Timer) Reset (d Duration) bool //重新设定timer t 的Duration d .func (t *Timer) Stop () bool //阻止timer 事件发生,当该函数执行后,timer 计时器停止,相应的事件不再执行
1 2 type Weekdayfunc (d Weekday) String () string //获取一周的字符串
一些例子: 获取年月日方法
1 2 3 4 5 6 7 8 9 t := time.Now() y := t.Year() m := int (t.Month()) d := t.Day() h := t.Hour() min := t.Minute() s := t.Second() fmt.Printf("%d-%d-%d" ,y,m,d) fmt.Printf("%d%02d%02d" ,y,m,d)
获取格式为:2017-12-29 16:58:39
1 2 3 4 t := time.Now() fmt.Println(t.String()[:19 ]) layout := "2006-01-02 15:04:05" fmt.Println(t.Format(layout))
获取三个小时之前的时间
1 2 du, _ := time.ParseDuration("-3h" ) t := time.Now().Add(du)
获取三天之前的时间
1 2 3 t := time.Now() t.AddDate(0 ,0 ,-3 ) fmt.Println(t)
t.AddDate(year,month,day) 正数向前,负数向后
时间戳转time.Time 类型
1 2 timestamp := 1513580645 t := time.Unix(timestamp,0 )
获取时间戳:
1 2 t := time.Now() timestamp := t.Unix()
两个时间的间隔
1 2 3 4 t1 := time.Now() t2 := time.Now() sub := t2.Since(t1)
字符串转时间
1 2 3 4 layout := "2006-01-02 15:04:05" t , err := time.Parse(layout,"2017-12-26 17:20:21" ) fmt.Println(t)
标准时间字符串转化为时间 使用byte读取数据库当中的timestamp字段时,会出现标准的时间格式
1 2 3 4 5 layout := "2006-01-02T15:04:05Z07:00" timeStr := "2018-01-02T11:30:21Z" t , _ := time.Parse(layout,timeStr) fmt.Println(t)
unicode 包常量 1 2 3 4 5 6 const ( MaxRune = '\U0010FFFF' ReplacementChar = '\uFFFD' MaxASCII = '\u007F' MaxLatin1 = '\u00FF' )
RangeTable 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 func Is (rangeTab *RangeTable, r rune ) bool type RangeTable struct { R16 []Range16 R32 []Range32 LatinOffset int } type Range16 struct { Lo uint16 Hi uint16 Stride uint16 } type Range32 struct { Lo uint32 Hi uint32 Stride uint32 }
判断及转换字符大小写、Title 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 func IsUpper (r rune ) bool func IsLower (r rune ) bool func IsTitle (r rune ) bool func ToUpper (r rune ) rune func ToLower (r rune ) rune func ToTitle (r rune ) rune func To (_case int , r rune ) rune
示例1:判断汉字:
1 2 3 4 5 6 7 8 9 func main () { for _, r := range "Hello 世界!" { if unicode.Is(unicode.Scripts["Han" ], r) { fmt.Printf("%c" , r) } } }
示例2:判断大小写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 func main () { for _, r := range "Hello ABC!" { if unicode.IsUpper(r) { fmt.Printf("%c" , r) } } for _, r := range "Hello abc!" { if unicode.IsLower(r) { fmt.Printf("%c" , r) } } for _, r := range "Hello ᾏᾟᾯ!" { if unicode.IsTitle(r) { fmt.Printf("%c" , r) } } }
示例3:输出 Unicode 规定的标题字符
1 2 3 4 5 6 7 func main () { for _, cr := range unicode.Lt.R16 { for i := cr.Lo; i <= cr.Hi; i += cr.Stride { fmt.Printf("%c" , i) } } }
示例4:转换大小写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 func main () { s := "Hello 世界!" for _, r := range s { fmt.Printf("%c" , unicode.ToUpper(r)) } for _, r := range s { fmt.Printf("%c" , unicode.ToLower(r)) } for _, r := range s { fmt.Printf("%c" , unicode.ToTitle(r)) } for _, r := range s { fmt.Printf("%c" , unicode.To(unicode.UpperCase, r)) } for _, r := range s { fmt.Printf("%c" , unicode.To(unicode.LowerCase, r)) } for _, r := range s { fmt.Printf("%c" , unicode.To(unicode.TitleCase, r)) } }
rune操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 func (special SpecialCase) ToUpper (r rune ) rune func (special SpecialCase) ToLower (r rune ) rune func (special SpecialCase) ToTitle (r rune ) rune type SpecialCase []CaseRangetype CaseRange struct { Lo uint32 Hi uint32 Delta d } const ( UpperCase = iota LowerCase TitleCase MaxCase ) const ( UpperLower = MaxRune + 1 )
eg.
1 2 3 4 5 6 7 8 9 10 11 12 func main () { s := "Hello 世界!" for _, r := range s { fmt.Printf("%c" , unicode.SpecialCase(unicode.CaseRanges).ToUpper(r)) } for _, r := range s { fmt.Printf("%c" , unicode.SpecialCase(unicode.CaseRanges).ToLower(r)) } for _, r := range s { fmt.Printf("%c" , unicode.SpecialCase(unicode.CaseRanges).ToTitle(r)) } }
SimpleFold 环绕查找 1 2 3 4 5 6 7 8 9 10 11 12 13 14 func SimpleFold (r rune ) rune
eg.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 func main () { s := "ΦφϕkKK" for _, c := range s { fmt.Printf("%x " , c) } fmt.Println() for _, v := range s { fmt.Printf("%c, %c, %c | %c -> %c\n" , unicode.ToUpper(v), unicode.ToLower(v), unicode.ToTitle(v), v, unicode.SimpleFold(v), ) } }
判断 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 func IsDigit (r rune ) bool func IsNumber (r rune ) bool func IsLetter (r rune ) bool func IsSpace (r rune ) bool func IsControl (r rune ) bool func IsGraphic (r rune ) bool func IsPrint (r rune ) bool func IsPunct (r rune ) bool func IsSymbol (r rune ) bool func IsMark (r rune ) bool func IsOneOf (set []*RangeTable, r rune ) bool
eg.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 func main () { fmt.Println() for _, r := range "Hello 123123一二三!" { if unicode.IsDigit(r) { fmt.Printf("%c" , r) } } fmt.Println() for _, r := range "Hello 123123一二三!" { if unicode.IsNumber(r) { fmt.Printf("%c" , r) } } fmt.Println() for _, r := range "Hello\n\t世界!" { if unicode.IsLetter(r) { fmt.Printf("%c" , r) } } fmt.Println() for _, r := range "Hello \t世 界!\n" { if unicode.IsSpace(r) { fmt.Printf("%q" , r) } } fmt.Println() for _, r := range "Hello\n\t世界!" { if unicode.IsControl(r) { fmt.Printf("%#q" , r) } } fmt.Println() for _, r := range "Hello 世界!\t" { if unicode.IsPrint(r) { fmt.Printf("%c" , r) } } fmt.Println() for _, r := range "Hello 世界!\t" { if unicode.IsGraphic(r) { fmt.Printf("%c" , r) } } fmt.Println() for _, r := range "Hello ៉៊់៌៍!" { if unicode.IsMark(r) { fmt.Printf("%c" , r) } } fmt.Println() for _, r := range "Hello 世界!" { if unicode.IsPunct(r) { fmt.Printf("%c" , r) } } fmt.Println() for _, r := range "Hello (<世=界>)" { if unicode.IsSymbol(r) { fmt.Printf("%c" , r) } } }
eg.判断汉字和标点:
1 2 3 4 5 6 7 8 9 func main () { set := []*unicode.RangeTable{unicode.Han, unicode.P} for _, r := range "Hello 世界!" { if unicode.IsOneOf(set, r) { fmt.Printf("%c" , r) } } }
eg.输出所有 mark 字符:
1 2 3 4 5 6 7 8 9 10 func main () { for _, cr := range unicode.M.R16 { Lo, Hi, Stride := rune (cr.Lo), rune (cr.Hi), rune (cr.Stride) for i := Lo; i >= Lo && i <= Hi; i += Stride { if unicode.IsMark(i) { fmt.Printf("%c" , i) } } } }
unicode/utf16 包1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 func IsSurrogate (r rune ) bool func EncodeRune (r rune ) (r1, r2 rune ) func DecodeRune (r1, r2 rune ) rune func Decode (s []uint16 ) []rune func Encode (s []rune ) []uint16
eg.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 func main () { fmt.Printf("%t, " , utf16.IsSurrogate(0xD400 )) fmt.Printf("%t, " , utf16.IsSurrogate(0xDC00 )) fmt.Printf("%t\n" , utf16.IsSurrogate(0xDFFF )) r1, r2 := utf16.EncodeRune('𠀾' ) fmt.Printf("%x, %x\n" , r1, r2) r := utf16.DecodeRune(0xD840 , 0xDC3E ) fmt.Printf("%c\n" , r) u := []uint16 {'不' , '会' , 0xD840 , 0xDC3E } s := utf16.Decode(u) fmt.Printf("%c" , s) }
unicode/utf8 包常量 1 2 3 4 5 6 7 const ( RuneError = '\uFFFD' RuneSelf = 0x80 MaxRune = '\U0010FFFF' UTFMax = 4 )
函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 func EncodeRune (p []byte , r rune ) int func DecodeRune (p []byte ) (r rune , size int ) func DecodeRuneInString (s string ) (r rune , size int ) func DecodeLastRune (p []byte ) (r rune , size int ) func DecodeLastRuneInString (s string ) (r rune , size int ) func FullRune (p []byte ) bool func FullRuneInString (s string ) bool func RuneCount (p []byte ) int func RuneCountInString (s string ) (n int ) func RuneLen (r rune ) int func RuneStart (b byte ) bool func Valid (p []byte ) bool func ValidString (s string ) bool func ValidRune (r rune ) bool
eg.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 func main () { b := make ([]byte , utf8.UTFMax) n := utf8.EncodeRune(b, '好' ) fmt.Printf("%v:%v\n" , b, n) r, n := utf8.DecodeRune(b) fmt.Printf("%c:%v\n" , r, n) s := "大家好" for i := 0 ; i < len (s); { r, n = utf8.DecodeRuneInString(s[i:]) fmt.Printf("%c:%v " , r, n) i += n } fmt.Println() for i := len (s); i > 0 ; { r, n = utf8.DecodeLastRuneInString(s[:i]) fmt.Printf("%c:%v " , r, n) i -= n } fmt.Println() b = []byte ("好" ) fmt.Printf("%t, " , utf8.FullRune(b)) fmt.Printf("%t, " , utf8.FullRune(b[1 :])) fmt.Printf("%t, " , utf8.FullRune(b[2 :])) fmt.Printf("%t, " , utf8.FullRune(b[:2 ])) fmt.Printf("%t\n" , utf8.FullRune(b[:1 ])) b = []byte ("大家好" ) fmt.Println(utf8.RuneCount(b)) fmt.Printf("%d, " , utf8.RuneLen('A' )) fmt.Printf("%d, " , utf8.RuneLen('\u03A6' )) fmt.Printf("%d, " , utf8.RuneLen('好' )) fmt.Printf("%d, " , utf8.RuneLen('\U0010FFFF' )) fmt.Printf("%d\n" , utf8.RuneLen(0x1FFFFFFF )) fmt.Printf("%t, " , utf8.RuneStart("好" [0 ])) fmt.Printf("%t, " , utf8.RuneStart("好" [1 ])) fmt.Printf("%t\n" , utf8.RuneStart("好" [2 ])) b = []byte ("你好" ) fmt.Printf("%t, " , utf8.Valid(b)) fmt.Printf("%t, " , utf8.Valid(b[1 :])) fmt.Printf("%t, " , utf8.Valid(b[2 :])) fmt.Printf("%t, " , utf8.Valid(b[:2 ])) fmt.Printf("%t, " , utf8.Valid(b[:1 ])) fmt.Printf("%t\n" , utf8.Valid(b[3 :])) fmt.Printf("%t, " , utf8.ValidRune('好' )) fmt.Printf("%t, " , utf8.ValidRune(0 )) fmt.Printf("%t, " , utf8.ValidRune(0xD800 )) fmt.Printf("%t\n" , utf8.ValidRune(0x10FFFFFF )) }
to be continued...