Go の変数スコープと関数リテラル: 「scopelint」の問題を理解する
Go コードでは、定義された変数を使用する必要がある場合があります。関数リテラルの範囲内ステートメント。ただし、これを行うと、「関数リテラル (scopelint) の範囲スコープ x の変数を使用しています」という lint エラーが発生する可能性があります。このエラーは、Go では、特に関数リテラルを操作する場合、変数のスコープに細心の注意を払う必要があるために発生します。
「関数リテラルの範囲スコープ x の変数を使用する」というエラーは、関数リテラル (匿名関数) が次のように渡されたことを示します。 t.Run のような組み込み関数のパラメーターは、範囲スコープ内に存在する変数 (ここでは x) を参照しています。ループ変数は値によってのみ使用できるため、関数リテラルが変数の古い値にアクセスする可能性があります。
次の例を考えてみましょう。
func TestGetUID(t *testing.T) { namespace := "lkfm" expecteduid := "fake_uid" var tests = []struct { description string expected string namespace string objs []runtime.Object }{ {"PositiveScenario", expecteduid, namespace, []runtime.Object{simpleNamespace(namespace)}}, } for _, x := range tests { t.Run(x.description, func(t *testing.T) { client := fake.NewSimpleClientset(x.objs...) actual := getUID(client, x.namespace) assert.Equal(t, x.expected, actual) }) } }
この例では、ループ変数 x は、t.Run に渡される関数リテラル内で使用されます。コンパイラは、ループが終了して x の値が変更された後に関数リテラルが実行されないことを保証できません。 x の意図された値と実際の値が一致しない可能性があるため、予測できない動作が発生する可能性があります。
この問題に対処するために、Go は新しいスコープ内のループ変数の値をキャプチャするメカニズムを提供します。これは、変数のコピーを作成するか、それを引数として関数リテラルに渡すことによって実現できます。たとえば、上記のコードは次のように書き換えることができます。
func TestGetUID(t *testing.T) { namespace := "lkfm" expecteduid := "fake_uid" var tests = []struct { description string expected string namespace string objs []runtime.Object }{ {"PositiveScenario", expecteduid, namespace, []runtime.Object{simpleNamespace(namespace)}}, } for _, test := range tests { namespaceCopy := test.namespace t.Run(test.description, func(t *testing.T) { client := fake.NewSimpleClientset(test.objs...) actual := getUID(client, namespaceCopy) assert.Equal(t, test.expected, actual) }) } }
test.namespace の値を新しい変数 namespaceCopy にコピーすることで、関数リテラルが namespace の定数値にアクセスできるようになります。これにより、データの不一致の可能性が排除され、関数リテラルの動作が予測可能になります。
要約すると、関数リテラル内でループ変数を使用する場合は、変数のスコープと変数に関連する潜在的な問題を慎重に考慮することが重要です。寿命。上記の手法を使用することで、開発者はコードの安全性と信頼性を確保できます。
以上がGo の「scopelint」問題: 関数リテラル内のループ変数をどのように処理しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。