Описание типов пакета Context

Описание типов пакета Context

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)) // конвертируем в правильный тип
}

Дополнительные рекомендации:

  1. Для production-кода:
// Лучше выносить ключи в package-level константы
const (
	LanguageKey favContextKey = "language"
	ColorKey    favContextKey = "color"
)
  1. Добавить проверку типа значения:
if v, ok := ctx.Value(k).(string); ok {
    fmt.Printf("Found string value: %s\n", v)
}
  1. Для сложных данных использовать указатели:
type configKey struct{}
ctx = context.WithValue(ctx, configKey{}, &MyConfig{...})

func WithoutCancel

func WithoutCancel(parent Context) Context

WithoutCancel возвращает производный контекст, который указывает на родительский контекст и не отменяется при отмене родительского контекста. Возвращаемый контекст не возвращает Deadline или Err, а его канал Done равен nil. Вызов Cause на возвращаемом контексте возвращает nil.