Функция reflect.Select

Функция reflect.Select выполняет выбор из набора каналов, аналогично оператору select в Go, но в рефлексии. Она принимает слайс из структуры reflect.SelectCase, которая описывает каждую операцию над каналом. Функция возвращает индекс выбранного случая, значение, полученное из канала (если это операция приема), и флаг, указывающий, было ли значение получено успешно. Эта функция является ключевым инструментом для динамической работы с каналами, когда структура операций выбора заранее неизвестна.

Синтаксис

goreflect.Select(cases []reflect.SelectCase) (chosen int, recv reflect.Value, recvOK bool)

Структура reflect.SelectCase

Структура reflect.SelectCase описывает один случай в операторе выбора. Она содержит три поля:

Пример 1: Блокирующий выбор

Давайте создадим два канала и выполним блокирующий выбор между ними:

gopackage main

import (
  "fmt"
  "reflect"
  "time"
)

func main() {
  ch1 := make(chan string)
  ch2 := make(chan string)

  go func() {
    time.Sleep(100 * time.Millisecond)
    ch1 <- "from channel 1"
  }()

  go func() {
    time.Sleep(50 * time.Millisecond)
    ch2 <- "from channel 2"
  }()

  cases := []reflect.SelectCase{
    {
      Dir:  reflect.SelectRecv,
      Chan: reflect.ValueOf(ch1),
    },
    {
      Dir:  reflect.SelectRecv,
      Chan: reflect.ValueOf(ch2),
    },
  }

  chosen, recv, recvOK := reflect.Select(cases)
  fmt.Printf("chosen: %d, recv: %s, recvOK: %t", chosen, recv.String(), recvOK)
}

Результат выполнения кода:

go"chosen: 1, recv: from channel 2, recvOK: true"

Пример 2: Отправка данных в канал

Давайте выполним операцию отправки данных в канал:

gopackage main

import (
  "fmt"
  "reflect"
)

func main() {
  ch := make(chan int, 1)
  cases := []reflect.SelectCase{
    {
      Dir:  reflect.SelectSend,
      Chan: reflect.ValueOf(ch),
      Send: reflect.ValueOf(12345),
    },
  }

  chosen, recv, recvOK := reflect.Select(cases)
  fmt.Printf("chosen: %d, recv: %s, recvOK: %t", chosen, recv.String(), recvOK)
}

Результат выполнения кода:

go"chosen: 0, recv: <invalid Value>, recvOK: false"

Пример 3: Неблокирующий выбор с default

Давайте используем операцию по умолчанию для неблокирующего выбора:

gopackage main

import (
  "fmt"
  "reflect"
)

func main() {
  ch := make(chan int)
  cases := []reflect.SelectCase{
    {
      Dir:  reflect.SelectRecv,
      Chan: reflect.ValueOf(ch),
    },
    {
      Dir: reflect.SelectDefault,
    },
  }

  chosen, recv, recvOK := reflect.Select(cases)
  fmt.Printf("chosen: %d, recv: %s, recvOK: %t", chosen, recv.String(), recvOK)
}

Результат выполнения кода:

go"chosen: 1, recv: <invalid Value>, recvOK: false"

Смотрите также

  • функцию reflect.MakeChan,
    которая создает канал в рефлексии
  • функцию reflect.ValueOf,
    которая возвращает значение как объект рефлексии
  • функцию reflect.TypeOf,
    которая возвращает тип значения в рефлексии
  • функцию reflect.DeepEqual,
    которая выполняет глубокое сравнение значений