ローカルヘルパークロージャ
ローカルヘルパー関数
- 関数内部でのみ使用する 匿名関数 (Anonymous Function) を変数に割り当てて使用する手法
- 親関数の変数を キャプチャ (Capture) することで、引数伝達を最小限に抑え、繰り返されるロジックを排除する
例
1func BuildControllers(ctx context.Context, controllerCtx ControllerContext, controllerDescriptors map[string]*ControllerDescriptor,
2 unsecuredMux *mux.PathRecorderMux, healthzHandler HealthCheckAdder) ([]Controller, error) {
3 ...
4 buildController := func(controllerDesc *ControllerDescriptor) error {
5 controllerName := controllerDesc.Name()
6 ctrl, err := controllerDesc.BuildController(ctx, controllerCtx)
7 ...
8 controllers = append(controllers, ctrl)
9 checks = append(checks, check)
10 return nil
11 }
12 ...
13 for _, controllerDesc := range controllerDescriptors {
14 ...
15 if err := buildController(controllerDesc); err != nil {
16 return nil, err
17 }
18 }
19 ...
20}
利点
- 重複コードの削除が可能
- 関数引数の単純化
- 関数引数の代わりに外部変数をキャプチャして使用(クロージャ)
- グローバル変数なしでの状態共有
- スコープ内のローカル変数を共有
- カプセル化/隔離
- スコープ内でのみ使用可能
注意
- 単体 テスト の作成不可
- 関数型プログラミングの観点からは 純粋でない (impure) 関数
- 過度な外部変数キャプチャは避けるべき
- 可読性のために短く保つのが良い
- ループ変数キャプチャの問題
- Go 1.21以下: ループ変数(
v)は、ループが実行されるたびに新しく生成されるのではなく、一つのメモリアドレスを継続的に上書きする- Go 1.22以上: ループの各反復 (Iteration) ごとに変数を 新しく生成 (Shadowing)