【Go言語】ファクトリー関数を使って構造体を生成する

ファクトリー関数とは

まずGoでは構造体からインスタンスを生成するとき、以下の3つの方法があります。

// 1. 構造体の宣言
type Person struct {
  FirstName string
  LastName  string
  Age       int
}

// newで作成
p := new(Person)

// var変数宣言で作成
var p Person

// 構造体リテラルで作成
p := &Person{
  FirstName: "John",
  LastName:  "Doe",
  Age:       30,
}

上記の方法以外に、ファクトリー関数を使って構造体のインスタンスを生成する方法があります。

ファクトリー関数とは、構造体のインスタンスを生成する関数のことです。Go言語では、構造体のコンストラクタがないため、ファクトリー関数を使って構造体のインスタンスを生成することがよくあります。

ファクトリー関数を利用するメリット

このファクトリー関数を利用するメリットは以下の2点です。

  • 入力値をバリデーションできる
  • ゼロ値以外の初期値を与えられる

メリットは他にもたくさんありますが、今回はこの2点に絞って説明します。

入力値をバリデーションできる

ファクトリー関数を利用すると、入力値をバリデーションできます。 バリデーションに関してはgo-validatorなどのライブラリを使うことも多々ありますが、簡単なバリデーションだったり、他のメリットを受ける場合であれば、ファクトリー関数を利用することもあります。

以下のように簡単なバリデーションを実装してみます。

// ユーザー情報を格納する構造体
type User struct {
    Name string
    Age  int
}

// ファクトリー関数
func NewUser(name string, age int) (*User, error) {
    if name == "" {
        return nil, errors.New("name is required")
    }
    if age < 0 {
        return nil, errors.New("age must be positive")
    }

    return &User{Name: name, Age: age}, nil
}

このとき以下のような入力値を与えると、エラーが返ってくるようになります。

user, err := NewUser("", 25)
if err != nil {
  fmt.Println("Error:", err)
  return
}
// Error: name is required
user, err := NewUser("John", -1)
if err != nil {
  fmt.Println("Error:", err)
  return
}
// Error: age must be positive

ゼロ値以外の初期値を与えられる

ファクトリー関数を利用すると、ゼロ値以外の初期値を与えられます。Goでは構造体を生成するときに値が与えられなかった場合、ゼロ値が与えられます。これを利用して以下のように構造体のフィールドに初期値を与えることができます。

type User struct {
    Name string
    Age  int
}

func NewUser(name string, age int) *User {
  if name == "" {
      name = "unknown"
  }
  return &User{Name: name, Age: age}
}

このとき、以下のように引数に空文字を与えると、unknownが与えられます。

user := NewUser("", 25)
fmt.Println(user.Name)
// &{unknown 25}

このように、ファクトリー関数を利用すると、構造体のインスタンスを生成するときにバリデーションを行ったり、ゼロ値以外の初期値を与えることができます。