はじめに
元ネタはtenntennさんの伝説カンファレンスの一部になります。
https://www.youtube.com/watch?v=X0tzCL5gqr8
コードリーディング会とは何人かで同じコードを各々で読んで、発見を共有して理解を深めましょう!というのが趣旨と理解しています。しかし知人で一緒にGoを学んでくれる人も見つけられず、悲しくも一人でコードリーディング会を開催することになりました。
やってみたら読めない箇所が多すぎました。1文ずつ嚙み砕いてGo言語の理解を深めていく作業になりました。その過程の不明点と解釈を記事にして公表していこうと思います。僕と同じ程度の理解度(初学者)の方が、不明点を理解するきっかけになればうれしいです。
※1日の学びを1記事にするので情報量は少なめです。徐々に情報量を増やして有益な記事を書けるよう頑張ります。
※個人の解釈を投稿する記事なので誤った情報が多々あると思います。申し訳ありませんがご了承ください。誤りについてはご指摘いただけるとうれしいです。
本記事は 4回目となり、 fmt
パッケージを読み進めます。
メモ
何の処理をしているか全然わからん
以下は fmt
パッケージの一部です。
var ppFree = sync.Pool{
New: func() any { return new(pp) },
}
https://cs.opensource.google/go/go/+/master:src/fmt/print.go;l=131;drc=master
理解するため手探りで調べていきました。
そもそもこの書き方なんだ?
var
で変数を宣言して、そのあと {...}
で括ってるからおそらく構造体だと思うけどワカランって感じでした。ですが sync.Pool
に注目すると、 sync
パッケージで定義されている構造体 Pool
だということがわかりました。
type Pool struct {
noCopy noCopy
local unsafe.Pointer // local fixed-size per-P pool, actual type is [P]poolLocal
localSize uintptr // size of the local array
victim unsafe.Pointer // local from previous cycle
victimSize uintptr // size of victims array
// New optionally specifies a function to generate
// a value when Get would otherwise return nil.
// It may not be changed concurrently with calls to Get.
New func() any
}
https://cs.opensource.google/go/go/+/master:src/sync/pool.go;drc=master;l=44
New:
ってなんだ?
先ほど引用した構造体 Pool
の中にも
New func() any
とあるし、これと関連してそうなのは固いなあと思いつつ、new関数に関連しそうと思ってました。その勘違いが沼にハマる原因でした。そもそも構造体って、
type 構造体名 struct {
フィールド名 型
}
みたいな構文だし、new関数であれば new(...)
みたいに ()
が必要でした。それなのに僕は、「newってなんか見たことあるな。[Go golang New]で検索っと。あっ、new関数ってのがあるぞ。これっぽいな」と間違った解釈をしていました。(ちなみにnewは予約語ではなく事前宣言名なので変数名として利用できます。ややこしい。)少し話がそれてきたので本筋に戻すと、 New
はフィールド名でした。
そうなると以下のコード
New: func() any { return new(pp) },
は次のように見えてきました。
フィールド名: 何か
「この形どこかで見たことあるぞ、、、」と思ったらスライスの代入で使う
{インデックス番号: 要素, インデックス番号: 要素, ... }
のように感じました。そこで適当なコードをPlayground書いて検証してみました。
package main
import "fmt"
type pool struct {
New string
}
var ppFree = pool{
New: "hoge",
}
func main() {
fmt.Println("Hello, 世界")
fmt.Println(ppFree.New)
}
https://go.dev/play/p/fzlcd4QhSpw
(改めて思うと当たり前な気がしますが、構造体のフィールドにはアクセス修飾子 .
を使うと思い込んでました。)
よくわからない ,
コレ
さっきのPlaygroundを少しいじってみました。まず普通に消してみました。するとエラーになります。
var ppFree = pool{
New: "hoge" //「,」消した
}
エラー内容は「syntax error: unexpected newline, expecting comma or }
」です。 ,
か }
が必要だよ!!って言われてます。なのでこうしてみました。エラーは出ませんでした。
var ppFree = pool{
New: "hoge"}
でもなんか気持ち悪いですよね。これでもOKみたいです。
var ppFree = pool{New: "hoge"}
大本のコードにカンマ ,
がついている理由は構文的な理由なんですね。(Gopher道場の動画でこれのこと言ってたきがするなあ。と思いました。)
あとは func() any { return new(pp) }
ここだけ
ちなみにGo17.7ではこのようになっています。Go1.18からは型エイリアス any
が導入されると良く耳にしますよね。
var ppFree = sync.Pool{
New: func() interface{} { return new(pp) },
}
無名関数を実行して戻り値をインタフェース型で受け取り、 return
で返すのは pp
型の無名変数を返すとわかります。( pp
は構造体)
type pp struct {
buf buffer
// arg holds the current item, as an interface{}.
arg any
// value is used instead of arg for reflect values.
value reflect.Value
// fmt is used to format basic items such as integers or strings.
fmt fmt
// reordered records whether the format string used argument reordering.
reordered bool
// goodArgNum records whether the most recent reordering directive was valid.
goodArgNum bool
// panicking is set by catchPanic to avoid infinite panic, recover, panic, ... recursion.
panicking bool
// erroring is set when printing an error string to guard against calling handleMethods.
erroring bool
// wrapErrs is set when the format string may contain a %w verb.
wrapErrs bool
// wrappedErr records the target of the %w verb.
wrappedErr error
}
最後に
何もわからんから、なんとなく処理が追える状態になってうれしいです。
余談
現時刻(2/16 0:04)から洗濯物を干していきます。めんどくさ。