go泛型体验

2022-03-16  本文已影响0人  wwq2020

背景

有了泛型可以做到复用,比如sort,filter,map,reduce等常用方法,这里举个ch的例子
我们写go时候经常会进行ch的fanin,fanout操作,但是没有泛型时候,没办法写针对任何类型的(类型安全,不考虑类型安全的话可以传入interface{}然后通过反射来做到)

例子


package main

import (
    "fmt"
    "reflect"
)

func FanOut[T any](chs ...chan T) chan<- T {
    ret := make(chan T)
    recvChValue := reflect.ValueOf(ret)
    sendChValues := make([]reflect.Value, 0, len(chs))
    for _, ch := range chs {
        value := reflect.ValueOf(ch)
        sendChValues = append(sendChValues, value)
    }
    go func() {
        for {
            value, ok := recvChValue.Recv()
            for _, sendChValue := range sendChValues {
                if !ok {
                    sendChValue.Close()
                    continue
                }
                sendChValue.Send(value)
            }

            if !ok {
                return
            }
        }
    }()
    return ret
}

func FanIn[T any](chs ...chan T) <-chan T {
    ret := make(chan T)
    cases := make([]reflect.SelectCase, 0, len(chs))
    for _, ch := range chs {
        value := reflect.ValueOf(ch)
        item := reflect.SelectCase{
            Dir:  reflect.SelectRecv,
            Chan: value,
        }
        cases = append(cases, item)
    }
    go func() {
        for {
            chosen, recvValue, ok := reflect.Select(cases)
            if !ok {
                curCases := make([]reflect.SelectCase, 0, len(chs))
                for idx, each := range cases {
                    if chosen == idx {
                        curCases = append(curCases, cases[idx+1:]...)
                        break
                    }
                    curCases = append(curCases, each)
                }
                if len(curCases) == 0 {
                    close(ret)
                    return
                }

                cases = curCases
                continue
            }

            ret <- recvValue.Interface().(T)
        }
    }()
    return ret
}

func main() {
    fanInCh1 := make(chan int, 1)
    fanInCh2 := make(chan int, 1)
    fanInCh := FanIn(fanInCh1, fanInCh2)
    fanInCh1 <- 1
    fmt.Println(<-fanInCh)
    fanInCh2 <- 2
    fmt.Println(<-fanInCh)
    close(fanInCh1)
    fanInCh2 <- 3
    fmt.Println(<-fanInCh)
    close(fanInCh2)
    fmt.Println(<-fanInCh)

    fanOutCh1 := make(chan int, 1)
    fanOutCh2 := make(chan int, 1)
    fanOutCh := FanOut(fanOutCh1, fanOutCh2)
    fanOutCh <- 1
    fmt.Println(<-fanOutCh1, <-fanOutCh2)
    close(fanOutCh)
    fmt.Println(<-fanOutCh1, <-fanOutCh2)

}


上一篇 下一篇

猜你喜欢

热点阅读