Concurrency
context.WithValue: 文字列キーを共有すると値が衝突する
同じ文字列キーを使うWithValueは、より内側で設定した値が前の値を隠します。
Sourcevalue_key.go
Go 1.22
package contextflow
import "context"
type userIDKey struct{}
func StringKeyCollision() string {
ctx := context.WithValue(context.Background(), "user-id", "application")
ctx = context.WithValue(ctx, "user-id", "middleware")
return ctx.Value("user-id").(string)
}
func PrivateKeyDoesNotCollide() (string, string) {
ctx := context.WithValue(context.Background(), "user-id", "application")
ctx = context.WithValue(ctx, userIDKey{}, "middleware")
return ctx.Value("user-id").(string), ctx.Value(userIDKey{}).(string)
}Testvalue_key_test.go
Go 1.22
package contextflow
import "testing"
func TestContextWithValueで文字列キーを共有すると値が衝突する(t *testing.T) {
if got := StringKeyCollision(); got != "middleware" {
t.Fatalf("StringKeyCollision() = %q, want middleware", got)
}
application, middleware := PrivateKeyDoesNotCollide()
if application != "application" || middleware != "middleware" {
t.Fatalf("PrivateKeyDoesNotCollide() = %q, %q", application, middleware)
}
}01Assertion
このテストで確認できること
- applicationとmiddlewareが同じ文字列キーを使う
- 内側のmiddleware値がapplication値を隠す
- 非公開の独自型キーなら両方を保持できる
contextの値はリクエストスコープの横断的な少量データに限定します。衝突を避けるため、キーは非公開の独自型を使い、関数引数として渡すべき依存をcontextへ隠しません。
OBSERVED RESULT
"user-id" → middleware
userIDKey{} → middleware
string key remains separately → application