🦫

Go1.22のリリースで本業で即利用できそうなものをまとめてみた

2024/02/28に公開

本業でGoを使っており、備忘録として、Go1.22で導入された新しい機能のうちすぐに利用できそうなものをまとめた。

TL;DR

  • database/sqlNull[T] は独自で型定義しているとき、 Scan などの実装をスキップできる
  • slicesConcat

1. database/sqlNull[T]

独自の型を定義をしている場合以下のように読み取り( Scan )と書き込み( Value )用の実装することがある

type Email string

func (e *Email) Validate() error {
	r, err := regexp.Compile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
	if err != nil {
		return err
	}

	if !r.MatchString(string(*e)) {
		return errors.New("invalid email")
	}

	return nil
}

func (e *Email) Scan(value any) error {
	switch t := value.(type) {
	case string:
		*e = Email(t)
		return e.Validate()
	case []byte:
		*e = Email(t)
		return e.Validate()
	}

	return errors.New("invalid type")
}

func (e Email) Value() (driver.Value, error) {
	return string(e), nil
}

このとき、emailのカラムがDBでNULL許容なカラム立った場合、以前までは以下のようにする必要があった。

func (e *NullEmail) Scan(value any) error {
	if value == nil {
		e.Email, e.Valid = "", false
		return nil
	}

	e.Valid = true
	return e.Email.Scan(value)
}

func (e NullEmail) Value() (driver.Value, error) {
	if !e.Valid {
		return nil, nil
	}

	return e.Email.Value()
}

これが自前で実装の必要がなく、以下のようにするだけでよくなった。

type User struct {
	// 以下のように利用箇所で定義するだけ
	Email sql.Null[Email]
}

2. slicesConcat

これはかなりシンプルで2つ以上の配列から、一つの配列を作るもの。
これまでは以下のようにちょっと気持ち悪い感じのコードを書いていた。

arr1 := []string{"a", "b", "c"}
arr2 := []string{"d", "e", "f"}
arr3 := []string{"g", "h", "i"}
arr := append(arr1, append(arr2, arr3...)...) // arr = [a b c d e f g h i]

これが以下だけでよくなります。

arr1 := []string{"a", "b", "c"}
arr2 := []string{"d", "e", "f"}
arr3 := []string{"g", "h", "i"}
arr = slices.Concat(arr1, arr2, arr3) // arr = [a b c d e f g h i]

slices.Concat の内部的には、slices.Grow を使っていて、渡された引数のSliceの長さを計算して、必要な分だけメモリを確保しているためメモリ効率も良い。

所感

今回まとめた2つのうち特に Null[T] はすでにこれを使わずに実装している部分があり、そのコードが不要になりそうなので、リファクタリングしたいと思っている。

今回追加にはならなかったが、range over funcは気になる。習得したらプログラムの書き方を大幅にアップデートできそうな気がするので早めにキャッチアップしていきたい。一方でGoの良さの一つであるシンプルさが失われないかどうかは確認しておきたい。

Discussion