やりたいこと
Goでフィールドにアクセスする際、nilの構造体のオブジェクトに対してフィールドを参照しようとしてにるぽ(ぬるぽ)になることは結構やりがちです。
なので多くの場合は参照前に明示的にnilチェックをすると思いますが、頻繁にアクセスするフィールドなどは取得メソッドを挟むようにすることで事故率を下げられるかもしれません。
サンプル
TeamのオブジェクトをUserのフィールドで、UserのオブジェクトをCommentのフィールドで持つ形になっています。
type Team struct {
ID string
Name string
}
type User struct {
ID string
Name string
Email string
Team *Team
}
type Comment struct {
ID string
text string
User *User
}
取得用のメソッド
func (u *User) SafeTeam() *Team {
if u == nil {
return nil
}
return u.Team
}
func (u *User) SafeTeamID() (*Team, bool) {
if u == nil {
return nil, false
}
return u.Team, true
}
func (u *User) TeamWithResult() (*Team, bool) {
if u == nil {
return nil, false
}
return u.Team, true
}
func (c *Comment) Team() *Team {
if c == nil || c.User == nil {
return nil
}
return c.User.Team
}
呼び出した例
func hoge(u *User) error {
if t := u.SafeTeam(); t == nil {
return errors.New("could not get team")
}
fmt.Println(u.SafeTeamID())
if t, ok := u.TeamWithResult(); !ok {
return errors.New("could not get team")
}
}
func fugo(c *Comment) error {
t := c.Team()
if t == nil {
return errors.New("could not get team")
}
}
まとめ
今回のコードはシンプルですし、一人で開発している分には事前にnilチェック入れればいいように思えるかもしれません。
ただ、大人数での開発や長期間に渡る保守・追加開発を考慮すると、こういった安全装置がじわじわと効いてくることはあると思います。
もっと良いやり方があればコメントなどで教えていただけると嬉しいです。