🐡

【go】reflectパッケージを使用してゼロ値であるかの関数を作成した

2024/09/15に公開

はじめに

こんにちは、daikiです!
普段はスクラム開発をしており、フロント・バック両方の開発をしており、
フロントはTypescript, Next.js。バックはgo, ginの言語、技術を触っています。

今回は、リクエストデータのある項目以外は送られていない判定をしたく、調べていたところ標準パッケージのreflectで実装できたので、記録に残しておきたいと思い、記事にしました。

使用技術

  • go v1.22

実装

if文でリクエストのフィールドを一つひとつ確認すれば、可能ではありますが、もっと良い方法を調べていたらreflectパッケージを使えばよりきれいに実装できそうなので、使っていきました。

// リクエストされる型
type Person struct {
	Name  string
	Age   int
	Hobby *string
}

Person型がリクエストされる型だとして、Nameだけがリクエストされているか確認したいといった状況だとします。

func IsNameOnlyRequest(person Person) bool {
	if person.Name == "" {
		return false
	}
	values := reflect.ValueOf(person)

	for i := range values.NumField() {
		filed := values.Field(i)
		filedName := values.Type().Field(i).Name

		if filedName == "Name" {
			continue
		}

		if !filed.IsZero() {
			return false
		}
	}
	return true
}

Nameだけがリクエストされているかの確認のため、最初にNameが空文字ではないことを確認しています。
その後、ValueOfでreflect.Value型のインスタンスを返すようにします。
それぞれのフィールドの内容を確認したいため、for rangeで繰り返し処理をして、フィールドとフィールド名をiで取得しました。
フィールド名がNameの場合は次の繰り返し処理にいき、そうでない場合はゼロ値であるかを確認してリクエストされていないことを確認しています。

テストコード

ポインタ型部分が気になったので、以下のようなテストコードも作成しました。
ポインタ型のゼロ値は空文字ではなく、nilなので問題なさそうです。

func TestIsNameOnlyRequest(t *testing.T) {
	testCases := map[string]struct {
		req    Person
		expect bool
	}{
		"Nameのみのリクエストの場合、true": {
			req:    Person{Name: "test"},
			expect: true,
		},
		"Ageもリクエストしている場合、false": {
			req:    Person{Name: "test", Age: 100},
			expect: false,
		},
		"Hobbyもリクエストしている場合、false": {
			req:    sql.Person{Name: "test", Hobby: stringToPtr("プログラミング")},
			expect: false,
		},
		"Hobbyもリクエストしている場合(空文字)、false": {
			req:    Person{Name: "test", Hobby: stringToPtr("")},
			expect: false,
		},
		"すべて初期値でリクエストしている場合、false": {
			req:    Person{},
			expect: false,
		},
	}

	for _, tc := range testCases {
		actual := IsNameOnlyRequest(tc.req)
		assert.Equal(t, tc.expect, actual)
	}
}

最後に

今回はrelfectパッケージを使って関数を作成しました。
正直relfectパッケージを使っていなかったので、今回の実装とこの記事の作成でrelfectパッケージを以前よりも何ができるのか知ることができました。
引き続き、業務や自己学習で学んだことを記事にまとめていきたいと思います。

参考記事

https://pkg.go.dev/reflect

Discussion