context.WithValue создаёт новый контекст с привязанной парой ключ-значение. Используется для передачи request-scoped данных через цепочку вызовов — request ID, ID юзера, trace ID.
type ctxKey string
const userIDKey ctxKey = "user_id"
ctx := context.WithValue(r.Context(), userIDKey, 42)
// дальше в глубине вызовов:
if id, ok := ctx.Value(userIDKey).(int); ok {
fmt.Println(id) // 42
}
Важно использовать unexported тип для ключа (как ctxKey выше), иначе другой пакет может случайно перезаписать твоё значение. Под капотом каждый WithValue оборачивает родительский контекст — получается цепочка. Поиск значения идёт по этой цепочке линейно, поэтому не стоит пихать туда всё подряд. Контекст — не замена аргументов функций. Туда кладут только cross-cutting concerns: трейсинг, аутентификацию, логирование.