🦔

Go における「継承的」機能:構造体の埋め込み(備忘録)

2024/09/14に公開

はじめに

Go には継承という概念がないものの、類似の機能は存在し、ORM ライブラリの中でも利用されています。
この実装は以前から存在したものの、GORM のリファレンスを読んで見かけたこと、実際に使ってみて思ったより便利だったことから、備忘録的に残します。

GORM での実装例

GORM では、よくあるベースモデルとしてgorm.Modelが提供されています。

// gorm.Model definition
type Model struct {
  ID        uint           `gorm:"primaryKey"`
  CreatedAt time.Time
  UpdatedAt time.Time
  DeletedAt gorm.DeletedAt `gorm:"index"`
}

https://gorm.io/docs/models.html#gorm-Model

このモデルを自作のモデルに埋め込むことで、楽ができます。

type User struct {
  gorm.Model
  Name string
}

https://gorm.io/docs/models.html#gorm-Model

これが GORM で提供されているEmbedded Structになります。
この Go に存在する構造体の埋め込みを利用して継承的なことをやってみます。

実装例:baseModel と Book

今回は、ベースとなるモデル、baseModelBookモデルを使って実装してみます。
以下実装例です。

main.go
package main

import (
    "fmt"
    "time"
)

type baseModel struct {
    ID        string
    CreatedAt time.Time
}

func (b *baseModel) create() {
    b.CreatedAt = time.Now()
    fmt.Printf("Base model created with ID: %s at %v\n", b.ID, b.CreatedAt)
}

type Book struct {
    baseModel // 構造体の埋め込み
    Title     string
}

func (b *Book) displayInfo() {
    fmt.Printf("Book: %s (ID: %s, Created: %v)\n", b.Title, b.ID, b.CreatedAt)
}

func main() {
    book := &Book{
        baseModel: baseModel{ID: "1"},
        Title:     "Go Programming",
    }

    // baseModelのメソッドを呼び出し
    book.create()

    // Bookのメソッドを呼び出し
    book.displayInfo()
}

こんな感じで、オブジェクト指向っぽいことができます。便利!

構造体埋め込みの注意点

構造体埋め込みには少し注意点があります。
Go の仕様的な話で、異なるpackage間で使う場合、埋め込んだ構造体のメソッドや値が他の言語のような雰囲気で簡単には利用できないので、要注意です。

参考文献

https://gorm.io/docs/models.html#gorm-Model

Discussion