# Go でステータスを型で表現する ```go // ステータスを型で表現したサンプルコード // DDD + 型システムのイメージ // Go の場合は代数的データ型が使えないので、ジェネリクスを使っている package main import ( "fmt" "reflect" ) type Status interface { status() } type FooStatus struct{} type BarStatus struct{} func (FooStatus) status() {} func (BarStatus) status() {} // DB から取得したユーザ情報 type RawUser struct { id int name string // status は DB から取得した生の文字列 status string } // アプリ内で使うユーザ情報 type UserBase interface { GetID() int GetName() string } // ステータスを持つユーザ情報 type User[S Status] struct { id int name string } func (u User[S]) GetID() int { return u.id } func (u User[S]) GetName() string { return u.name } // 確認用 func PrintStatus(u UserBase) { fmt.Println(reflect.TypeOf(u)) } // ステータスを変更するメソッド // Foo から Bar にしか変更できない func (u User[FooStatus]) ChangeStatusToBar() User[BarStatus] { return User[BarStatus]{id: u.id, name: u.name} } // 使いやすいようにエイリアスを作成 type FooUser = User[FooStatus] type BarUser = User[BarStatus] // DB からユーザ情報を取得する関数 func LoadUserFromDB(id int) (UserBase, error) { // Load user from DB u := RawUser{id: id, name: "Alice", status: "foo"} switch u.status { case "foo": return FooUser{id: u.id, name: u.name}, nil case "bar": return BarUser{id: u.id, name: u.name}, nil } return nil, fmt.Errorf("unknown status: %s", u.status) } func main() { // DB からユーザ情報を取得 user, _ := LoadUserFromDB(1) PrintStatus(user) if fooUser, ok := user.(FooUser); ok { // ステータスを変更 barUser := fooUser.ChangeStatusToBar() PrintStatus(barUser) } } ```