-
標準パッケージでどのように使われているか
-
io.Readerとio.Writerがあることでどういう利点があるのか具体例を挙げて考えてみる
type Reader interface {
Read(p []byte) (n int, err error)
}
fmt.Fscan
は引数に io.Reader
をとる
func Fscan(r io.Reader, a ...interface{}) (n int, err error) {
s, old := newScanState(r, true, false)
n, err = s.doScan(a)
s.free(old)
return
}
fmt.Scan
でfmt.Fscan
にos.Stdin
を渡している
func Scan(a ...interface{}) (n int, err error) {
return Fscan(os.Stdin, a...)
}
os.Stdin
は下記のように定義されている
var (
Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
...
...
)
os.NewFile
は *os.File
を返す
func NewFile(fd uintptr, name string) *File {
kind := kindNewFile
if nb, err := unix.IsNonblock(int(fd)); err == nil && nb {
kind = kindNonBlock
}
return newFile(fd, name, kind)
}
*os.File
は io.Reader
を実装している
func (f *File) Read(b []byte) (n int, err error) {
if err := f.checkValid("read"); err != nil {
return 0, err
}
n, e := f.read(b)
return n, f.wrapErr("read", e)
}
そのためfmt.Fscan
は引数に os.Stdin
を取れる
type Writer interface {
Write(p []byte) (n int, err error)
}
fmt.Fprint
はio.Writer
を引数に取る
func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
p := newPrinter()
p.doPrint(a)
n, err = w.Write(p.buf)
p.free()
return
}
fmt.Print
でfmt.Fprint
にos.Stdout
を渡している
func Print(a ...interface{}) (n int, err error) {
return Fprint(os.Stdout, a...)
}
os.Stdout
は下記のように定義されている
var (
...
Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
...
)
os.NewFile
は *os.File
を返す
func NewFile(fd uintptr, name string) *File {
kind := kindNewFile
if nb, err := unix.IsNonblock(int(fd)); err == nil && nb {
kind = kindNonBlock
}
return newFile(fd, name, kind)
}
*os.File
は io.Reader
を実装している
func (f *File) Write(b []byte) (n int, err error) {
if err := f.checkValid("write"); err != nil {
return 0, err
}
n, e := f.write(b)
if n < 0 {
n = 0
}
if n != len(b) {
err = io.ErrShortWrite
}
epipecheck(f, e)
if e != nil {
err = f.wrapErr("write", e)
}
return n, err
}
そのためfmt.Fprint
は引数に os.Stdout
を取れる
-
幅広い箇所に拡張が可能
http
パッケージやbytes
パッケージ 、strings
パッケージで使用されている
-
Mock テストが用意になる
- 標準入出力の代わりにバイトで渡すということが可能