Описание типов пакета Context
Categories:
type CancelCauseFunc
type CancelCauseFunc func(cause error)
CancelCauseFunc
ведет себя как CancelFunc
, но дополнительно устанавливает причину отмены. Эту причину можно получить, вызвав Cause
на отмененном Context
или на любом из его производных Context
.
Если контекст уже был отменен, CancelCauseFunc
не устанавливает причину. Например, если childContext
является производным от parentContext
:
- если parentContext отменен с причиной cause1 до того, как childContext отменен с причиной cause2, то Cause(parentContext) == Cause(childContext) == cause1
- если childContext отменен с причиной cause2 до того, как parentContext отменен с причиной cause1, то Cause(parentContext) == cause1 и Cause(childContext) == cause2
type CancelFunc
type CancelFunc func()
CancelFunc
сообщает операции о необходимости прекратить работу. CancelFunc
не ждет, пока работа будет остановлена. CancelFunc
может вызываться несколькими goroutines
одновременно. После первого вызова последующие вызовы CancelFunc
ничего не делают.
type Context
type Context interface {
// Deadline возвращает время, когда работа, выполняемая от имени этого
// контекста должна быть отменена. Deadline возвращает ok==false, если
// срок не установлен. Последовательные вызовы Deadline возвращают
// одинаковые результаты.
Deadline() (deadline time.Time, ok bool)
// Done возвращает канал, который закрывается, когда работа, выполняемая
// от имени этого контекста, должна быть отменена. Done может возвращать
// nil, если этот контекст никогда не может быть отменен. Последовательные
// вызовы Done возвращают одинаковое значение.
// Закрытие канала Done может происходить асинхронно,
// после возврата функции cancel.
//
// WithCancel организует закрытие Done при вызове cancel;
// WithDeadline организует закрытие Done по истечении срока;
// WithTimeout организует закрытие Done по истечении таймаута
//.
//
// Done предоставляется для использования в операторах select:
//
// // Stream генерирует значения с помощью DoSomething и отправляет их в out,
// // пока DoSomething не вернет ошибку или ctx.Done не будет закрыт.
// func Stream(ctx context.Context, out chan<- Value) error {
// for {
// v, err := DoSomething(ctx)
// if err != nil {
// return err
// }
// select {
// case <-ctx.Done():
// return ctx.Err()
// case out <- v:
// }
// }
// }
//
// См. https://blog.golang.org/pipelines для получения дополнительных примеров
// использования канала Done для отмены.
Done() <-chan struct{}
// Если Done еще не закрыт, Err возвращает nil.
// Если Done закрыт, Err возвращает no-nil ошибку, объясняющую причину:
// DeadlineExceeded, если срок контекста истек, или Canceled, если контекст
// был отменен по какой-либо другой причине.
// После того, как Err возвращает ошибку, отличную от nil, последующие вызовы
// Err возвращают ту же ошибку.
Err() error
// Value возвращает значение, связанное с этим контекстом для ключа, или nil,
// если с ключом не связано никакое значение. Последовательные вызовы Value с
// одним и тем же ключом возвращают один и тот же результат.
//
// Используйте значения контекста только для данных в рамках запроса, которые
// проходят через процессы и границы API, а не для передачи опциональных
// параметров в функции.
//
// Ключ идентифицирует конкретное значение в контексте. Функции, которые хотят
// сохранить значения в контексте, обычно выделяют ключ в глобальной
// переменной, а затем используют этот ключ в качестве аргумента для
// context.WithValue и Context.Value. Ключ может быть любого типа, который
// поддерживает равенство;
// пакеты должны определять ключи как неэкспортируемый тип, чтобы избежать коллизий.
//
// Пакеты, которые определяют ключ контекста, должны предоставлять типобезопасные
// аксессоры для значений, хранящихся с использованием этого ключа:
//
// // Пользователь пакета определяет тип User, который хранится в контекстах.
// пакет user
//
// import «context»
//
// // User — это тип значения, хранящегося в Contexts.
// type User struct {...}
//
// // key — это неэкспортируемый тип для ключей, определенных в этом пакете.
// // Это предотвращает конфликты с ключами, определенными в других пакетах.
// type key int
//
// // userKey — ключ для значений user.User в Contexts. Он
// // не экспортируется; клиенты используют user.NewContext и user.FromContext
// // вместо прямого использования этого ключа.
// var userKey key
//
// // NewContext возвращает новый Context, который несет значение u.
// func NewContext(ctx context.Context, u *User) context.Context {
// return context.WithValue(ctx, userKey, u)
// }
//
// // FromContext возвращает значение User, хранящееся в ctx, если оно есть.
// func FromContext(ctx context.Context) (*User, bool) {
// u, ok := ctx.Value(userKey).(*User)
// return u, ok
// }
Value(key any) any
}
Context
несет в себе срок, сигнал отмены и другие значения через границы API.
Методы контекста могут вызываться несколькими goroutines
одновременно.
func Background
func Background() Context
Background
возвращает непустой Context
, не равный nil
. Он никогда не отменяется, не имеет значений и не имеет срока действия. Обычно он используется главной функцией, инициализацией и тестами, а также в качестве Context
верхнего уровня для входящих запросов.
func TODO
func TODO() Context
TODO
возвращает непустой Context
, не равный nil
. Код должен использовать context.TODO
, когда неясно, какой Context
использовать, или он еще не доступен (потому что окружающая функция еще не была расширена для приема параметра Context
).
func WithValue
func WithValue(parent Context, key, val any) Context
WithValue
возвращает производный контекст, который указывает на родительский Context
. В производном контексте значение, связанное с ключом, является val
.
Используйте контекстные значения только для данных в рамках запроса, которые проходят через процессы и API
, а не для передачи опциональных параметров функциям.
Предоставленный ключ должен быть сопоставимым и не должен быть типом string
или любым другим встроенным типом, чтобы избежать конфликтов между пакетами, использующими контекст. Пользователи WithValue
должны определять свои собственные типы для ключей. Чтобы избежать выделения памяти при присвоении interface {}
, ключи контекста часто имеют конкретный тип struct {}
. В качестве альтернативы статический тип экспортированных переменных ключей контекста должен быть указателем или интерфейсом.
Пример
Этот пример демонстрирует, как можно передать значение в контекст, а также как получить его, если оно существует.
package main
import (
"context"
"fmt"
)
func main() {
// Определяем пользовательский тип для ключей контекста
type favContextKey string
// Функция для поиска значения в контексте
lookupValue := func(ctx context.Context, k favContextKey) {
if v := ctx.Value(k); v != nil {
fmt.Printf("Found value for key '%s': %v\n", k, v)
return
}
fmt.Printf("Key '%s' not found in context\n", k)
}
// Создаем ключ и контекст со значением
languageKey := favContextKey("language")
ctx := context.WithValue(context.Background(), languageKey, "Go")
// Ищем существующее значение
lookupValue(ctx, languageKey)
// Ищем несуществующее значение
colorKey := favContextKey("color")
lookupValue(ctx, colorKey)
// Дополнительная проверка с другим типом (демонстрация безопасности)
otherKey := "otherKey" // обычная строка, не favContextKey
lookupValue(ctx, favContextKey(otherKey)) // конвертируем в правильный тип
}
Дополнительные рекомендации:
- Для production-кода:
// Лучше выносить ключи в package-level константы
const (
LanguageKey favContextKey = "language"
ColorKey favContextKey = "color"
)
- Добавить проверку типа значения:
if v, ok := ctx.Value(k).(string); ok {
fmt.Printf("Found string value: %s\n", v)
}
- Для сложных данных использовать указатели:
type configKey struct{}
ctx = context.WithValue(ctx, configKey{}, &MyConfig{...})
func WithoutCancel
func WithoutCancel(parent Context) Context
WithoutCancel
возвращает производный контекст, который указывает на родительский контекст и не отменяется при отмене родительского контекста. Возвращаемый контекст не возвращает Deadline
или Err
, а его канал Done
равен nil
. Вызов Cause
на возвращаемом контексте возвращает nil
.