GO/TESTS JAVA → TS →

Concurrency

context.WithValue: 文字列キーを共有すると値が衝突する

同じ文字列キーを使うWithValueは、より内側で設定した値が前の値を隠します。

Go 1.22+
concurrencycontextwith-valuekeycollisionapi-design
01 / 01 proof
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)
}
Source✓Test
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

Static index

教材を検索

テーマ、タグ、テスト名、カテゴリ、Goバージョンで絞り込みます。

37件の教材を表示しています。

Language · Go 1.22+string: len は文字数ではなくUTF-8のバイト数を返すTest 絵文字を含む文字列ではバイト数とrune数が異なるLanguage · Go 1.22+string: range のindexはrune番号ではなくバイト位置になるTest 文字列に対するrangeのindexはrune番号ではなくバイト位置になるCollections · Go 1.22+slice: 容量に余裕があるappendは同じ配列を書き換えるTest 容量に余裕があるsliceへのappendは同じバッキング配列を書き換えるCollections · Go 1.22+slice: nilと空sliceはJSONで異なるTest nilSliceと空sliceはJSONで異なる値になるCollections · Go 1.22+map: 存在しないキーも値だけを読むとゼロ値になるTest 存在しないmapキーも値だけを読むとゼロ値になるLanguage · Go 1.22+interface: nilポインタを入れたinterfaceはnilではないTest Nilポインタを入れたinterfaceはnilではないError Handling · Go 1.22+error: ラップした原因はerrors.Isで照合するTest ラップしたerrorはerrorsIsで原因と照合できるError Handling · Go 1.22+defer: 引数は登録時に評価され、呼び出しはLIFOになるTest Deferの引数はdefer文を実行した時点で評価されるConcurrency · Go 1.22+context: cancelされたcontextはcontext.Canceledを返すTest CancelしたcontextはcontextCanceledを返すConcurrency · Go 1.22+channel: 閉じたchannelの受信はゼロ値とfalseを返すTest 閉じたchannelの受信はゼロ値とfalseを返すDate / Time · Go 1.22+time.Time: 同じ瞬間でも==とEqualは異なるTest 同じ時刻でもlocationが異なるtimeTimeはEqualと比較結果が異なるEncoding · Go 1.22+encoding/json: omitemptyは数値のゼロ値を省略するTest OmitEmptyは数値のゼロ値をJSONから省略するConcurrency · Go 1.22+Go 1.22: range変数はgoroutineで各反復ごとに捕捉されるTest Go122ではrange変数をgoroutineが各反復ごとに捕捉するLanguage · Go 1.22+strings.Builder: 書き込み後にコピーするとpanicになるTest 書き込み後のstringsBuilderをコピーするとpanicになるLanguage · Go 1.22+string: []byteへの変換結果を変更しても元の文字列は変わらないTest StringをByteSliceへ変換して変更しても元の文字列は変わらないCollections · Go 1.22+map: nil mapは読み取りできても書き込みでpanicになるTest NilMapは読み取りできても書き込みでpanicになるCollections · Go 1.22+slices.Clone: 別のバッキング配列を作るTest SlicesCloneは別のバッキング配列を作るLanguage · Go 1.22+interface: sliceを格納した値同士の比較はpanicになるTest Sliceを持つinterface値同士の比較はpanicになるError Handling · Go 1.22+errors.Join: 複数の原因をerrors.Isで照合できるTest ErrorsJoinした複数の原因をErrorsIsで照合できるError Handling · Go 1.22+errors.As: ラップしたポインタ型の原因を取り出すTest ErrorsAsでポインタ型の原因を取り出せるError Handling · Go 1.22+defer: Closeのエラーは明示的に返さなければ失われるTest DeferしたCloseのエラーは明示的に返さなければ失われるConcurrency · Go 1.22+context: 期限切れはcontext.DeadlineExceededとして観測するTest Timeout期限切れはContextDeadlineExceededを返すConcurrency · Go 1.22+channel: nil channelを含むselect caseは無効になるTest NilChannelを含むSelectCaseは無効になるConcurrency · Go 1.22+sync.Once: panicしてもDoは再実行しないTest SyncOnceはPanicしても再実行しないEncoding · Go 1.22+encoding/json: 非公開フィールドはタグがあっても出力しないTest EncodingJsonは非公開フィールドを出力しないConcurrency · Go 1.22+sync.Map: Loadの結果は型アサーションなしに使えないTest SyncMapのLoad結果は型アサーションなしに使えないHTTP · Go 1.22+http.Response.Body: 読み終えた後にCloseするTest HTTPResponseBodyは読み終えた後にCloseするDate / Time · Go 1.22+time.Duration: 無単位の整数はナノ秒として扱われるTest 無単位のDurationはナノ秒として扱われるConcurrency · Go 1.22+context.WithValue: 文字列キーを共有すると値が衝突するTest ContextWithValueで文字列キーを共有すると値が衝突するLanguage · Go 1.22+range: 反復中にappendしても開始時の長さまでしか走査しないTest Range中にAppendしても反復回数は開始時の長さで固定されるError Handling · Go 1.22+recover: deferした関数から直接呼ばなければpanicを回復できないTest RecoverはDeferした関数から直接呼ばなければPanicを回復できないConcurrency · Go 1.22+channel: 閉じたchannelへ送信するとpanicになるTest 閉じたChannelへの送信はPanicになるEncoding · Go 1.22+encoding/json: 未知フィールドは既定で無視されるTest EncodingJsonは未知フィールドを既定で無視しDisallowUnknownFieldsで拒否できるConcurrency · Go 1.22+context: WithCancelCauseではErrとCauseが異なるTest WithCancelCauseではErrはCanceledでCauseは指定した原因になるCollections · Go 1.22+array と slice: 配列はコピーされsliceは要素を共有するTest 配列は値としてコピーされsliceは要素を共有するLanguage · Go 1.22+receiver: value receiverはコピー、pointer receiverは元を更新するTest valueReceiverはコピーを更新しpointerReceiverは呼び出し元を更新するConcurrency · Go 1.22+channel: buffered channelは容量まで受信者なしで送信できるTest bufferedChannelは受信者なしでも容量まで送信できる