Closed9

[Golang] io パッケージについて

takewelltakewell

IO すなわち Input と Output だが、このパッケージは OS のプリティティブなシステムコールを抽象化するラッパー。コンピューターの処理は Input 、読み込む reader, コンピューター(OS) からのOutput を書き込む writer のモジュールの二つに処理、もしくは 処理をする Input => Process => Output の構造になっている

takewelltakewell

まず io パッケージにを説明するためには基本的な io.Writer と io.Reader の理解が必要
そのために Go の hello world コードだがこの fmt.Println を紐解いていく。

package main

import "fmt"

func main() {
	msg := "hello world"
	fmt.Println(msg)
}

takewelltakewell

以下、Println の内訳

Fprintln(os.Stdout, a...) のラッパーであることがわかる。
引数は 標準出力と , 受け取った文字列のインターフェース

ちなみに返り値の n は 0

// Println formats using the default formats for its operands and writes to standard output.
// Spaces are always added between operands and a newline is appended.
// It returns the number of bytes written and any write error encountered.
func Println(a ...interface{}) (n int, err error) {
	return Fprintln(os.Stdout, a...)
}
takewelltakewell

次に Fprintln
メモリをアロケート、\n を末尾に挿入、w.Write を実行, メモリを解放 という中身に見える。

// Fprintln formats using the default formats for its operands and writes to w.
// Spaces are always added between operands and a newline is appended.
// It returns the number of bytes written and any write error encountered.
func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
	p := newPrinter()
	p.doPrintln(a)
	n, err = w.Write(p.buf)
	p.free()
	return
}
takewelltakewell

次に w.Write というやつに行きつき、その中の f.write(b) というやつの先に f.pfd.Write(b) という
syscall.Write というやつにたとどりつく、この実態はファイルディスクリプターというやつで
整数値 1 が入っている
こういう経路をだとって標準出力 hello world をえているわけだ。

// Write writes len(b) bytes to the File.
// It returns the number of bytes written and an error, if any.
// Write returns a non-nil error when n != len(b).
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
}
// write writes len(b) bytes to the File.
// It returns the number of bytes written and an error, if any.
func (f *File) write(b []byte) (n int, err error) {
	n, err = f.pfd.Write(b)
	runtime.KeepAlive(f)
	return n, err
}
// Write implements io.Writer.
func (fd *FD) Write(p []byte) (int, error) {
	if err := fd.writeLock(); err != nil {
		return 0, err
	}
	defer fd.writeUnlock()
	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
		return 0, err
	}
	var nn int
	for {
		max := len(p)
		if fd.IsStream && max-nn > maxRW {
			max = nn + maxRW
		}
		n, err := ignoringEINTRIO(syscall.Write, fd.Sysfd, p[nn:max])
		if n > 0 {
			nn += n
		}
		if nn == len(p) {
			return nn, err
		}
		if err == syscall.EAGAIN && fd.pd.pollable() {
			if err = fd.pd.waitWrite(fd.isFile); err == nil {
				continue
			}
		}
		if err != nil {
			return nn, err
		}
		if n == 0 {
			return nn, io.ErrUnexpectedEOF
		}
	}
}
takewelltakewell

ここで注目したいのが io.Writer 、これはつまり出力について扱うための抽象化されたインターフェースである。

このスクラップは2022/03/29にクローズされました