Go 源碼 bytes-buffer-go 閱讀

【導讀】緩衝區,實現了大小控制,字節切片和 string 類型的讀寫,同時還對情況進行了優化,比如存在 bootstrap,比如 grow 函數中的多次檢定。源碼讀精讀來學習。

Overview

這是 bytes 包裏的 buffer 實現

一圖勝千言

看不懂圖的再看下面吧

buffer.jpg

核心函數

Buffer 結構

這是 buffer 的內部結構
buf 字節切片,用來存儲 buffer 的內容
off 是代表從哪裏開始讀
bootstrap 用來作爲字節切片過小的時候防止多次申請空間減小開銷
lastRead 用來記錄上一次的操作

// A Buffer is a variable-sized buffer of bytes with Read and Write methods.
// The zero value for Buffer is an empty buffer ready to use.
// 注意 buffer 的零值是空的 buf
type Buffer struct {
 buf       []byte   // contents are the bytes buf[off : len(buf)]
 off       int      // read at &buf[off], write at &buf[len(buf)]
 bootstrap [64]byte // memory to hold first slice; helps small buffers avoid allocation.
 lastRead  readOp   // last read operation, so that Unread* can work correctly.

 // FIXME: it would be advisable to align Buffer to cachelines to avoid false
 // sharing.
}

Grow(n int)

申請擴展緩衝區

// Grow grows the buffer's capacity, if necessary, to guarantee space for
// another n bytes. After Grow(n), at least n bytes can be written to the
// buffer without another allocation.
// If n is negative, Grow will panic.
// If the buffer can't grow it will panic with ErrTooLarge.
// 增加容量 n byte
func (b *Buffer) Grow(n int) {
 if n < 0 {
  panic("bytes.Buffer.Grow: negative count")
 }
 m := b.grow(n)
 b.buf = b.buf[:m]
}

WriteString(s string) (n int, err error)

向 buffer 中寫字符串

// WriteString appends the contents of s to the buffer, growing the buffer as
// needed. The return value n is the length of s; err is always nil. If the
// buffer becomes too large, WriteString will panic with ErrTooLarge.
// 直接寫 string 也行,同時自動擴展
func (b *Buffer) WriteString(s string) (n int, err error) {
 b.lastRead = opInvalid
 //先嚐試不用擴展容量的寫法
 m, ok := b.tryGrowByReslice(len(s))
 if !ok {
  m = b.grow(len(s))
 }
 // copy 可以直接把 string 類型作爲 字節切片拷貝過去
 return copy(b.buf[m:], s), nil
}

也有寫字節切片的形式 Write(p []byte) (n int, err error)

ReadFrom(r io.Reader) (n int64, err error)

從 io.Reader 讀取數據到 buffer 中

// ReadFrom reads data from r until EOF and appends it to the buffer, growing
// the buffer as needed. The return value n is the number of bytes read. Any
// error except io.EOF encountered during the read is also returned. If the
// buffer becomes too large, ReadFrom will panic with ErrTooLarge.
// 從實現了 io.Reader 接口的 r 中讀取到 EOF 爲止,如果超出了 maxInt 那麼大就會返回太
// 大不能通過一個 [maxInt]byte 字節切片來存儲了
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
 b.lastRead = opInvalid
 for {
  i := b.grow(MinRead)
  // grow 申請了 n 個空間之後,會將 buffer 中的字節切片延長長度到 n 個字節之後
  // 所以需要重新賦值一下長度,避免一些誤解,保證長度都是有效數據提供的
  b.buf = b.buf[:i]
  // 將 r 中的數據讀到 buffer 中去
  m, e := r.Read(b.buf[i:cap(b.buf)])
  if m < 0 {
   panic(errNegativeRead)
  }

  // 手動更改長度
  b.buf = b.buf[:i+m]
  n += int64(m)
  if e == io.EOF {
   return n, nil // e is EOF, so return nil explicitly
  }
  if e != nil {
   return n, e
  }
 }
}

WriteTo(w io.Writer) (n int64, err error)

向 io.Writer 中寫數據

// WriteTo writes data to w until the buffer is drained or an error occurs.
// The return value n is the number of bytes written; it always fits into an
// int, but it is int64 to match the io.WriterTo interface. Any error
// encountered during the write is also returned.
func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
 b.lastRead = opInvalid
 if nBytes := b.Len(); nBytes > 0 {
  //從 off 開始讀的地方算起,全部寫到 io.Writer 中去
  m, e := w.Write(b.buf[b.off:])
  //寫的多了就報錯
  if m > nBytes {
   panic("bytes.Buffer.WriteTo: invalid Write count")
  }
  //記錄寫過了多少,位移 offset 指針
  b.off += m

  n = int64(m)
  if e != nil {
   return n, e
  }
  // all bytes should have been written, by definition of
  // Write method in io.Writer
  // 因爲剛纔判斷過寫多了的情況,所以這裏是寫少了
  if m != nBytes {
   return n, io.ErrShortWrite
  }
 }
 // Buffer is now empty; reset.
 // 寫完之後重置
 b.Reset()
 return n, nil
}

ReadBytes(delim byte) (line []byte, err error)

用來讀到終止符就結束,返回的是一個 line 字節切片包含終止符前的數據

// ReadBytes reads until the first occurrence of delim in the input,
// returning a slice containing the data up to and including the delimiter.
// If ReadBytes encounters an error before finding a delimiter,
// it returns the data read before the error and the error itself (often io.EOF).
// ReadBytes returns err != nil if and only if the returned data does not end in
// delim.
// 讀取到終止符爲止,就結束
func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) {
 slice, err := b.readSlice(delim)
 // return a copy of slice. The buffer's backing array may
 // be overwritten by later calls.
 line = append(line, slice...)
 return line, err
}

NewBuffer(buf []byte) *Buffer

用來新建一個新的 Buffer ,其實也可以使用 new 和 var 來聲明

// NewBuffer creates and initializes a new Buffer using buf as its
// initial contents. The new Buffer takes ownership of buf, and the
// caller should not use buf after this call. NewBuffer is intended to
// prepare a Buffer to read existing data. It can also be used to size
// the internal buffer for writing. To do that, buf should have the
// desired capacity but a length of zero.
//
// In most cases, new(Buffer) (or just declaring a Buffer variable) is
// sufficient to initialize a Buffer.
// 通過字節切片創建一個 buffer ,字節切片會保留初始值
// 在渴望容量但是長度爲 0?的情況下
// 也可以當作內核的 buffer 來寫入
func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} }

同時也有通過 string 類型的實現
**func NewBufferString(s string) *Buffer {return &Buffer{buf: []byte(s)}}**

總結

緩衝區,實現了大小控制,字節切片和 string 類型的讀寫,同時還對情況進行了優化,比如存在 bootstrap,比如 grow 函數中的多次檢定。適合多讀精讀來學習

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/teF1-oTpqXjXtav6TiTxWg