io.discard
是Go語言標準庫提供一個結構體型別,其在丟棄不需要的資料場景下非常好用。本文我們將從io.discard
型別的基本定義出發,講述其基本使用和實現原理,接著簡單描述 io.discard
的使用場景,基於此完成對 io.discard
型別的介紹。
io.discard
是 Go語言提供的一個Writer
,這個Writer
比較特殊,其不會做任何事情。它會將寫入的資料立即丟棄,不會做任何處理。其定義如下:
type discard struct{}
func (discard) Write(p []byte) (int, error) {}
func (discard) WriteString(s string) (int, error) {}
func (discard) ReadFrom(r Reader) (n int64, err error) {}
discard
結構體型別沒有定義任何欄位,同時還提供了Write
,ReadFrom
和WriteString
方法,Write
方法和WriteString
方法分別接收位元組切片和字串,然後返回寫入的位元組數。
同時還實現了io.ReaderFrom
介面,這個是為了在使用 io.Copy
函數時,將資料從源複製到io.discard
時,避免不必要的操作。
從上面discard
的定義可以看起來,其不是一個公開型別的結構體型別,所以我們並不能建立結構體範例。事實上Go語言提供了一個io.discard
範例的預定義常數,我們直接使用,無需自己建立範例,定義如下:
var Discard Writer = discard{}
下面通過一個丟棄網路連線中不再需要的資料的例子,來展示io.Discard
的使用,程式碼範例如下:
package main
import (
"fmt"
"io"
"net"
"os"
)
func discardData(conn net.Conn, bytesToDiscard int64) error {
_, err := io.CopyN(io.Discard, conn, bytesToDiscard)
return err
}
func main() {
conn, err := net.Dial("tcp", "example.com:80")
if err != nil {
fmt.Println("連線錯誤:", err)
return
}
defer conn.Close()
bytesToDiscard := int64(1024) // 要丟棄的位元組數
err = discardData(conn, bytesToDiscard)
if err != nil {
fmt.Println("丟棄資料錯誤:", err)
return
}
fmt.Println("資料已成功丟棄。")
}
在上面範例中,我們建立了網路連線,然後連線中的前1024個位元組的資料是不需要的。這個時候,我們通過io.CopyN
函數將資料從conn
拷貝到io.Discard
當中,基於io.Discard
丟棄資料的特性,成功將連線的前1024個位元組丟棄掉,而不需要自定義緩衝區之類的操作,簡單高效。
io.Discard
的目的是在某些場景下提供一個滿足io.Writer
介面的範例,但使用者對於資料的寫入操作並不關心。它可以被用作一個黑洞般的寫入目標,默默地丟棄所有寫入它的資料。所以io.discard
的實現也相對比較簡單,不對輸入的資料進行任何處理即可,下面我們來看具體的實現。
首先是io.discard
結構體的定義,沒有定義任何欄位,因為本來也不需要執行任何寫入操作:
type discard struct{}
而對於Write
和 WriteString
方法,其直接返回了傳入引數的長度,往該Writer
寫入的資料不會被寫入到其他地方,而是被直接丟棄:
func (discard) Write(p []byte) (int, error) {
return len(p), nil
}
func (discard) WriteString(s string) (int, error) {
return len(s), nil
}
同時discard
也實現了io.ReaderFrom
介面,實現了ReadFrom
方法,實現也是非常簡單,從blackHolePool
緩衝池中獲取位元組切片,然後不斷讀取資料,讀取完成之後,再將位元組切片重新放入緩衝池當中:
// 存在一個位元組切片緩衝池
var blackHolePool = sync.Pool{
New: func() any {
b := make([]byte, 8192)
return &b
},
}
func (discard) ReadFrom(r Reader) (n int64, err error) {
// 從緩衝池中取出一個 位元組切片
bufp := blackHolePool.Get().(*[]byte)
readSize := 0
for {
// 不斷讀取資料,bufp 只是作為一個讀取資料的中介,讀取到的資料並無意義
readSize, err = r.Read(*bufp)
n += int64(readSize)
if err != nil {
// 將位元組切片 重新放入到 blackHolePool 當中
blackHolePool.Put(bufp)
if err == EOF {
return n, nil
}
return
}
}
}
在io.Copy
函數中,將呼叫discard
中的ReadFrom
方法,能夠將Writer
中的所有資料讀取完,然後丟棄掉。
io.Discard
給我們提供了一個io.Writer
介面的範例,同時其又不會真實得寫入資料,這個在某些場景下非常有用。
有時候,我們可能需要一個實現io.Writer
介面的範例,但是我們並不關心資料寫入Writer
的結果,也不關心資料是否寫到了哪個地方,此時io.Discard
就給我們提供了一個方便的解決方案。同時io.Discard
可以作為一個黑洞寫入目標,能夠將資料默默丟棄掉,不會進行實際的處理和儲存。
所以如果我們想要丟棄某些資料,亦或者是需要一個io.Writer
介面的範例,但是對於寫入結果不需要關注時,此時使用io.Discard
是非常合適的。
io.discard
函數是Go語言標準庫中一個實現了Writer
介面的結構體型別,能夠悄無聲息得實現資料的丟棄。 我們先從io.discard
型別的基本定義出發,之後通過一個簡單的範例,展示如何使用io.discard
型別實現對不需要資料的丟棄。
接著我們講述了io.discard
型別的實現原理,其實就是不對寫入的資料執行任何操作。在使用場景下,我們想要丟棄某些資料,亦或者是需要一個io.Writer
介面的範例,但是對於寫入結果不需要關注時,此時使用io.Discard
是非常合適的。
基於此,便完成了對io.discard
型別的介紹,希望對你有所幫助。