今日の運動は腹筋ローラー,スクワット,縄跳び(両足跳)をした。統計を 運動の記録 にまとめる。

go の generics の扱い

今日はほぼまる一日コードを書いていた。あるデータ型のリファクタリングをしていて次のような constraint とメソッドの組み合わせで型チェックできることを理解した。generics 使って1年以上開発しているので感覚的にも慣れてきた。User と Group のどちらかを受け取る constraint とそのデータストアの定義は次のようになる。

type UserOrGroup interface {
	User | Group
	GetPrimaryID() string
}

type UserOrGroupStore[E UserOrGroup] interface {
	generic.Store[E]
	FindByPrimaryID(ctx context.Context, primaryID string) (*E, error)
}

この型定義を使う関数では次のようになる。

func find[
	E entry.UserOrGroup,
](
	ctx context.Context, store entry.UserOrGroupStore[E], primaryID string,
) (*E, error) {
	e, err := store.FindByPrimaryID(ctx, primaryID)
	if err != nil {
        ...
    }
	ee := *e
    // ee.PrimaryID はコンパイルが通らない
	_ = ee.GetPrimaryID() // 現時点ではメソッド呼び出しが必要
}

ここで UserOrGroup に GetPrimaryID() というメソッドを追加している。本来は両方の構造体に保持するメンバー属性ではあるものの、現時点の go のコンパイラはメンバー属性を正しくチェックできない。そのため、メソッドにして generics の型チェックが正しく通るようにしないといけない。go の issue にも上がっているのでいずれはメンバー属性を解決できるようになるのだろうと推測する。