Go io.Discard ใช้ตอนไหน

วันนี้เจอคำถามใน FB Group Golang Thailand ว่า ioutil.Discard (ตั้งแต่ 1.16 ioutil.Discard ถูกย้ายไป io.Discard แล้ว) ควรใช้ตอนไหน เลยไปค้นใน standard lib ว่าเขาใช้ตอนไหนกันบ้าง

ผมเลือกไปค้นใน package path “net” แล้วก็ path อื่นๆที่อยู่ภายใต้ “net” ด้วย ค้นเจอว่ามีการใช้ io.Discard แบบนี้

$ pwd
/Users/weerasak/src/go/src/net
$ ag "io\.Discard"
http/httputil/dump.go
135:			io.Copy(io.Discard, req.Body)

http/server.go
1371:			_, err := io.CopyN(io.Discard, w.reqBody, maxPostHandlerReadBytes+1)
3494:		io.Copy(io.Discard, mb)

http/fcgi/child.go
316:	io.CopyN(io.Discard, body, 100<<20)


http/client.go
697:				io.CopyN(io.Discard, resp.Body, maxBodySlurpSize)

http/transfer.go
375:			nextra, err = t.doBodyCopy(io.Discard, body)
997:			n, err = io.CopyN(io.Discard, bodyLocked{b}, maxPostHandlerReadBytes)
1008:		_, err = io.Copy(io.Discard, bodyLocked{b})

จะเห็นว่าเขาใช้ io.Discard โดยการ copy (เรียกใช้ io.Copy) ข้อมูลจาก io.Reader (type ที่ implements interface io.Reader) แล้วเขียนไปที่ io.Discard ที่เป็น io.Writer (type ที่ implements io.Writer)

ใน document ของ io.Discard เขียนเอาไว้ว่า

var Discard Writer = discard{}

// Discard is a Writer on which all Write calls succeed without doing anything.

นั่นคือเราเขียนข้อมูลไปที่ io.Discard มันจะเขียนได้สำเร็จ แต่มันไม่ได้ทำอะไรทั้งนั้นล่ะ

ดังนั้นที่เราเห็นโค้ด copy ข้อมูลไปใส่ io.Discard มันคือการ flush ข้อมูล io.Reader ทิ้งนั้นเอง

ถ้าใครเขียน shell คงเคยเห็น pattern แบบนี้

$ grep -r hello /sys/ 2> /dev/null

ที่หมายถึงเอาข้อมูลจาก standard error (file descriptor number 2) redirect ไปที่ /dev/null ซึ่งมันก็จะ redirect ไปทิ้งเฉยๆ ไม่มีอะไรเกิดขึ้น ซึ่งการใช้งาน io.Copy ไปที่ io.Discard จะเหมือน pattern ที่ใช้การ redirect ไปที่ /dev/null ของ shell นั่นเอง