# 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)
}
}
```