Source
確認したい最小のGoコードだけを置きます。
Go 1.22 / testing
説明より先に、実行できる境界条件を見る。Go by Tests は、Sourceとtestingを並べて読むためのExecutable Documentationです。
The method
確認したい最小のGoコードだけを置きます。
testingパッケージで、挙動をそのまま固定します。
値、nil、error、signalを短い結果として残します。
First observation
GoのstringはUTF-8バイト列であり、絵文字を含むとlenとrune数は一致しません。
package stringexample
import "unicode/utf8"
func ByteLen(value string) int {
return len(value)
}
func RuneLen(value string) int {
return utf8.RuneCountInString(value)
}package stringexample
import "testing"
func Test絵文字を含む文字列ではバイト数とrune数が異なる(t *testing.T) {
value := "Go🐹"
if got := ByteLen(value); got != 6 {
t.Fatalf("ByteLen() = %d, want 6", got)
}
if got := RuneLen(value); got != 3 {
t.Fatalf("RuneLen() = %d, want 3", got)
}
}Initial catalog
GoのstringはUTF-8バイト列であり、絵文字を含むとlenとrune数は一致しません。
Go 1.22+→02文字列をrangeするとruneを取り出せますが、indexはUTF-8のバイトオフセットです。
Go 1.22+→03appendが必ず新しい配列を確保するとは限らず、元のsliceと配列を共有することがあります。
Go 1.22+→04どちらもlenは0ですが、nil sliceはJSONでnull、空sliceは[]になります。
Go 1.22+→05mapの読み取りは未登録でも要素型のゼロ値を返すため、値だけでは存在を判定できません。
Go 1.22+→06型情報とnil値を持つinterfaceは、値だけがnilのinterfaceとは異なります。
Go 1.22+→07fmt.Errorfの%wで文脈を付けたerrorは、直接比較ではなくerrors.Isで原因を確認します。
Go 1.22+→08deferは関数終了時に実行されますが、引数はdefer文を通過した時点で評価されます。
Go 1.22+→09contextのキャンセルはDoneチャネルを閉じ、Errからcontext.Canceledとして観測できます。
Go 1.22+→10channelを閉じた後でも受信は直ちに返り、値のゼロ値とok=falseで終了を示します。
Go 1.22+→11==はlocationなどの内部表現も比較しますが、Equalは同じ時点を表すか比較します。
Go 1.22+→12omitemptyを付けたintは0のときJSONから消えるため、0と未指定を区別できません。
Go 1.22+→13Go 1.22以降はrangeのループ変数が反復ごとに新しくなるため、goroutine内の値が分離されます。
Go 1.22+→14書き込み済みのstrings.Builderを値コピーして再利用すると、実行時にpanicします。
Go 1.22+→15stringを[]byteへ変換すると、変更可能な別のバイト列として扱えます。
Go 1.22+→16nil mapへの読み取りはゼロ値を返しますが、代入するとpanicします。
Go 1.22+→17slices.Cloneで複製したsliceを変更しても、元のsliceは書き換わりません。
Go 1.22+→18interface自体は比較可能でも、動的な値がsliceなら==の評価時にpanicします。
Go 1.22+→19errors.Joinでまとめたエラーは、含まれる各原因をerrors.Isで見つけられます。
Go 1.22+→20errors.Asはラップ階層から目的の具体的なエラー型を取り出せます。
Go 1.22+→21deferでCloseを呼ぶだけでは、その失敗を関数の返り値へ反映できません。
Go 1.22+→22WithTimeoutやWithDeadlineで期限が切れると、Errはcontext.DeadlineExceededになります。
Go 1.22+→23nil channelの送受信caseはselectから外れ、defaultがあればdefaultが選ばれます。
Go 1.22+→24Once.Doの関数がpanicしても、そのOnceは完了済みとして扱われます。
Go 1.22+→25encoding/jsonは小文字で始まる非公開フィールドをJSONの対象にしません。
Go 1.22+→26sync.Mapは値をanyとして返すため、読み出し側で期待する型を確認する必要があります。
Go 1.22+→27HTTPレスポンスのBodyは読み終えた後に必ずcloseし、接続を適切に解放します。
Go 1.22+→28time.Durationへ直接渡した整数は、ミリ秒でなくナノ秒を表します。
Go 1.22+→29同じ文字列キーを使うWithValueは、より内側で設定した値が前の値を隠します。
Go 1.22+→30rangeが対象にする反復回数は開始時に決まり、ループ中にappendした要素を追加で走査しません。
Go 1.22+→31recoverをヘルパー関数へ委譲すると、panicは回復されずに呼び出し元へ伝播します。
Go 1.22+→32close済みのchannelに送信すると、受信のゼロ値とは異なり実行時panicになります。
Go 1.22+→33json.Unmarshalはstructに存在しないキーを既定で無視し、DecoderのDisallowUnknownFieldsで拒否できます。
Go 1.22+→34キャンセル状態はcontext.Canceledのままで、業務上の失敗原因はcontext.Causeから取り出します。
Go 1.22+→35配列の引数は値として渡り、sliceの要素変更は呼び出し元へ反映されます。
Go 1.22+→36value receiverの変更は呼び出し元へ残らず、pointer receiverの変更は元の値へ反映されます。
Go 1.22+→37buffered channelは空き容量がある間、受信側を待たずに送信を受け付けます。
Go 1.22+→