You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

133 lines
1.7 KiB
Go

package main
import (
"context"
"fmt"
"time"
)
func Aggregate[T any](cs ...<-chan T) <-chan T {
agg := make(chan T)
go func() {
defer close(agg)
for {
closed := 0
for _, c := range cs {
select {
case value, more := <-c:
if more {
agg <- value
} else {
closed++
}
default:
}
}
if closed == len(cs) {
break
}
}
}()
return agg
}
type TargetChan[T any] struct {
c <-chan T
target *T
}
type TryReceiver interface {
TryReceive() bool
}
func (tc TargetChan[T]) TryReceive() bool {
select {
case value := <-tc.c:
*tc.target = value
return true
default:
return false
}
}
func AwaitFirst(cancel context.CancelFunc, ws ...TryReceiver) {
done := make(chan struct{})
go func() {
defer close(done)
for {
for _, w := range ws {
if w.TryReceive() {
done <- struct{}{}
return
}
}
}
}()
<-done
cancel()
return
}
func main() {
c1 := make(chan string)
c2 := make(chan int)
c3 := make(chan float64)
c := context.Background()
c, cancel := context.WithCancel(c)
go func() {
defer close(c1)
for {
select {
case <-c.Done():
return
case <-time.After(300 * time.Millisecond):
}
c1 <- "1"
}
}()
go func() {
defer close(c2)
for {
select {
case <-c.Done():
return
case <-time.After(400 * time.Millisecond):
}
c2 <- 2
}
}()
go func() {
defer close(c3)
for {
select {
case <-c.Done():
return
case <-time.After(200 * time.Millisecond):
}
c3 <- 3.0
}
}()
var result1 string
var result2 int
var result3 float64
AwaitFirst(
cancel,
TargetChan[string]{c1, &result1},
TargetChan[int]{c2, &result2},
TargetChan[float64]{c3, &result3},
)
fmt.Println(result1, result2, result3)
}