package yetAnotherNewFunc

import (
    "fmt"
    "reflect"
    "sync"
    "testing"
)

type Foo struct{}

func NewFoo() *Foo {
    return &Foo{}
}

func YieldFoo() Foo {
    return Foo{}
}

func SpawnFoo(F func(interface{}) error) chan Foo {
    chFoo := make(chan Foo)
    go func() {
        for {
            x := <-chFoo
            F(x)
        }
    }()
    return chFoo
}

func NSpawnFoo(N int, F func(interface{}) error) []chan Foo {
    NFoo := make([]chan Foo, 0, N)
    for i := 0; i < N; i++ {
        NFoo = append(NFoo, SpawnFoo(F))
    }
    return NFoo
}

func IsFoo(x interface{}) (ret bool) {
    return reflect.TypeOf(Foo{}) == reflect.ValueOf(x).Type()
}

func ExampleFoo() {

    n := 5
    var wg sync.WaitGroup
    wg.Add(n)

    f := func(x interface{}) error { fmt.Printf("%T => %v\n", x, IsFoo(x)); wg.Done(); return nil }
    NSF := NSpawnFoo(n, f)

    for _, ch := range NSF {
        ch <- YieldFoo()
    }
    wg.Wait()

    // Output:
    // yetAnotherNewFunc.Foo => true
    // yetAnotherNewFunc.Foo => true
    // yetAnotherNewFunc.Foo => true
    // yetAnotherNewFunc.Foo => true
    // yetAnotherNewFunc.Foo => true
}

func (f Foo) Bar() {}

type FooBar interface {
    Bar()
}

func MustFooBar(x interface{}) FooBar {
    return x.(FooBar)
}

func TestMustFooBar(t *testing.T) {
    caseTable := []struct {
        Case interface{}
        Want bool
    }{
        {Foo{}, true},
        {struct{}{}, false},
    }

    for _, tc := range caseTable {
        defer func() {
            if e := recover(); e != nil && tc.Want {
                t.Errorf("MustFooBar(%v) panic, %v", tc.Case, e)
            }
        }()
        _ = MustFooBar(tc.Case)
    }
}

fizzbuzz with 'knock group'

package main

import (
    "flag"
    "fmt"
    "io"
    "net/http"
    "strconv"
    "sync"
)

var (
    vol = flag.Int("v", 100, "volume")
    max = flag.Int("m", 10000, "send numbers")
)

type msg struct {
    Q int
    A int
    I interface{}
}

type comm struct {
    Sch chan msg
    Rch chan msg
}

type reply struct {
    Comm chan *comm
}

var (
    poolSub chan reply = make(chan reply)
    poolAdd chan *comm = make(chan *comm)
)

var (
    standbyPub chan reply = make(chan reply)
    standbyOk  chan *comm = make(chan *comm)
)

func save() {
    var (
        pool    []*comm = make([]*comm, 0, *vol)
        standby []*comm = make([]*comm, 0, *vol)
    )
    for {
        select {
        case x := <-poolSub:
            last := len(pool) - 1
            if last > 0 {
                x.Comm <- pool[last]
                pool = pool[:last]
            } else {
                x.Comm <- nil
            }

        case x := <-poolAdd:
            standby = append(standby, x)

        case y := <-standbyPub:
            last := len(standby) - 1
            if last > 0 {
                y.Comm <- standby[last]
                standby = standby[:last]
            } else {
                y.Comm <- nil
            }

        case y := <-standbyOk:
            pool = append(pool, y)
        }
    }
}

func set() func(func(msg) msg) {
    var comms []comm
    for i := 0; i < *vol; i++ {
        comms = append(comms, comm{})
        comms[i].Sch = make(chan msg)
        comms[i].Rch = make(chan msg)
    }

    return func(g func(x msg) msg) {
        for i := 0; i < *vol; i++ {
            i := i
            rch := comms[i].Sch
            sch := comms[i].Rch
            poolAdd <- &comms[i]

            go func() {
                for {
                    x := <-rch
                    sch <- g(x)
                    poolAdd <- &comms[i]
                }
            }()
        }
    }
}

const (
    FIZZBUZZ = iota
    FIZZ
    BUZZ
    NOTFIZZBUZZ
)

func init() {
    flag.Parse()
    go save()

    f := set()
    g := func(m msg) msg {
        x := m.Q
        switch {
        case x%15 == 0:
            m.A = FIZZBUZZ
        case x%3 == 0:
            m.A = FIZZ
        case x%5 == 0:
            m.A = BUZZ
        default:
            m.A = NOTFIZZBUZZ
        }
        return m
    }
    f(g)
}

var ctrl chan struct{} = make(chan struct{})

func let() {
    close(ctrl)
}

func send(g func() msg) {
    for i := 0; i < *max; i++ {
        go func() {
            res := make(chan *comm)
            <-ctrl
            for {
                poolSub <- reply{res}
                c := <-res

                if c != nil {
                    c.Sch <- g()
                    break
                }
            }
            close(res)
        }()
    }
}

// done is for waiting all-received-timing
var done chan struct{} = make(chan struct{})

func wait() {
    <-done
}

func recv(f func(chan msg) error) {
    var wg sync.WaitGroup
    wg.Add(*max)
    go func() {
        for {
            res := make(chan *comm)
            standbyPub <- reply{res}
            c := <-res
            if c != nil {
                go func() {
                    f(c.Rch)
                    wg.Done()
                }()
                standbyOk <- c
            }
            close(res)
        }
    }()
    wg.Wait()
    close(done)
}

// knockGroup has writer for answering against the knock,
// and waitgroup of the knock.
type knockGroup struct {
    W  io.Writer
    WG *sync.WaitGroup
}

func main() {
    // "Knock-service"
    // GET http://localhost:8080/knock?k=n
    // then n'th fizzbuzz execute.
    f := func() func() msg {
        var n int

        knock := make(chan knockGroup)
        http.HandleFunc("/knock", func(w http.ResponseWriter, r *http.Request) {
            k := r.URL.Query().Get("k")
            var wg sync.WaitGroup
            if rep, err := strconv.Atoi(k); err == nil {
                wg.Add(rep)
                for ; rep > 0; rep-- {
                    knock <- knockGroup{w, &wg}
                }
            } else {
                wg.Add(1)
                knock <- knockGroup{w, &wg}
            }
            wg.Wait()
        })
        go http.ListenAndServe(":8080", nil)

        return func() msg {
            kG := <-knock
            n++
            return msg{Q: n, I: kG}
        }
    }
    // send and g sends numbers to setted goroutines
    g := f()
    go send(g)

    // recv and h processes the results from setted goroutines
    h := func(ch chan msg) error {
        m := <-ch

        var ans string
        switch m.A {
        case FIZZBUZZ:
            ans = "fizzbuzz"
        case FIZZ:
            ans = "fizz"
        case BUZZ:
            ans = "buzz"
        case NOTFIZZBUZZ:
            ans = "-"
        }

        fmt.Fprintf(m.I.(knockGroup).W, "%v%v%v\n", m.Q, ":", ans)
        m.I.(knockGroup).WG.Done()
        return nil
    }
    go recv(h)

    let()  // start
    wait() // wait
}

fizzbuzz timer

package main

import (
    "context"
    "fmt"
    "time"
)

const (
    FIZZBUZZ = iota
    FIZZ
    BUZZ
    NOTFIZZBUZZ
)

type result byte

func (r result) String() string {
    if r&(1<<FIZZBUZZ) > 0 {
        return "fizzbuzz"
    }
    if r&(1<<FIZZ) > 0 {
        return "fizz"
    }
    if r&(1<<BUZZ) > 0 {
        return "buzz"
    }
    if r&(1<<NOTFIZZBUZZ) > 0 {
        return "notFizzbuzz"
    }
    return "out-of-fizzbuzz"
}

func (r *result) Add(n int) error {
    p := *r
    *r = p | 1<<uint(n)
    return nil
}

func recv(ctx context.Context, in <-chan int) (q int64, r result) {
    defer func() { q = ctx.Value("q").(int64) }()
    for {
        select {
        case x := <-in:
            switch x {
            case FIZZBUZZ:
                defer r.Add(x)
                return
            case FIZZ:
                defer r.Add(x)
            case BUZZ:
                defer r.Add(x)
            case NOTFIZZBUZZ:
                defer r.Add(x)
                return
            }
        case <-ctx.Done():
            return
        }
    }
    return
}

func resPrint(q int64, r result) {
    fmt.Printf("%v %v %v\n", time.Unix(q/1000000000, q%1000000000).Format(time.RubyDate), q, r)
}

func launch(ctx context.Context, out chan<- int) {
    go do(ctx, 15, FIZZBUZZ, out)
    go do(ctx, 3, FIZZ, out)
    go do(ctx, 5, BUZZ, out)
    go dont(ctx, NOTFIZZBUZZ, out)
}

func do(ctx context.Context, d int64, a int, out chan<- int) error {
    q := ctx.Value("q").(int64)
    if q != 0 && q%d == 0 {
        select {
        case out <- a:
        case <-ctx.Done():
            return ctx.Err()
        }
    }
    return nil
}

func dont(ctx context.Context, a int, out chan<- int) error {
    q := ctx.Value("q").(int64)
    if q%3 != 0 && q%5 != 0 {
        select {
        case out <- a:
        case <-ctx.Done():
            return ctx.Err()
        }
    }
    return nil
}

func main() {
    for {
        now := time.Now().UnixNano()
        ctx := context.WithValue(context.Background(), "q", now)
        go func() {
            ctx, cancel := context.WithTimeout(ctx, 500*time.Millisecond)
            defer cancel()

            ch := make(chan int)
            go launch(ctx, ch)

            resPrint(recv(ctx, ch))
        }()
    }
}

import (
    "context"
    "flag"
    "fmt"
    "time"
)

const (
    FIZZBUZZ = iota
    FIZZ
    BUZZ
    NOTFIZZBUZZ
)

type msg struct {
    Q int
    A int
}

type ring struct {
    next *ring
    f    ringer
}

type ringer interface {
    Do(ctx context.Context, out chan<- msg) error
}

type fizzbuzz struct{}

func (fizzbuzz) Do(ctx context.Context, out chan<- msg) error {
    return do(ctx, 15, FIZZBUZZ, out)
}

type fizz struct{}

func (f fizz) Do(ctx context.Context, out chan<- msg) error {
    return do(ctx, 3, FIZZ, out)
}

type buzz struct{}

func (b buzz) Do(ctx context.Context, out chan<- msg) error {
    return do(ctx, 5, BUZZ, out)
}

func do(ctx context.Context, d, a int, out chan<- msg) error {
    n := ctx.Value("n")
    if n == nil {
        return fmt.Errorf("fizzbuzz-request-value is empty")
    }
    if n.(int)%d == 0 {
        select {
        case out <- msg{Q: n.(int), A: a}:
        case <-ctx.Done():
        }
    }
    return nil
}

type notFizzbuzz struct{}

func (nfb notFizzbuzz) Do(ctx context.Context, out chan<- msg) error {
    n := ctx.Value("n")
    if n == nil {
        return fmt.Errorf("fizzbuzz-request-value is empty")
    }
    if n.(int)%3 != 0 && n.(int)%5 != 0 {
        select {
        case out <- msg{Q: n.(int), A: NOTFIZZBUZZ}:
        case <-ctx.Done():
        }
    }
    return nil
}

func set() (*ring, int) {
    rings := []ring{
        {nil, fizzbuzz{}},
        {nil, fizz{}},
        {nil, buzz{}},
        {nil, notFizzbuzz{}},
    }

    for i := 0; i < len(rings); i++ {
        j := i + 1
        if j >= len(rings) {
            j = 0
        }
        rings[i].next = &rings[j]
    }

    return &rings[0], cap(rings)
}

var req chan int = make(chan int)

func circle(cur *ring, m int) {
    ctx := context.Background()
    for {
        i := <-req
        ctx := context.WithValue(ctx, "n", i)
        go func() {
            ctx, cancel := context.WithTimeout(ctx, 500*time.Millisecond)
            defer cancel()

            res := make(chan msg)
            go circleline(ctx, cur, m, res)

            fmt.Println(recv(ctx, res))
        }()
    }
}

func circleline(ctx context.Context, cur *ring, m int, out chan<- msg) {
    for ; m > 0; m-- {
        go cur.f.Do(ctx, out)
        cur = cur.next
    }
}

func recv(ctx context.Context, res <-chan msg) (buf struct {
    Q int
    A [4]string
    T string
}) {
    for {
        select {
        case x := <-res:
            defer func() { buf.Q = x.Q }()
            switch x.A {
            case FIZZBUZZ:
                defer func() { buf.A[FIZZBUZZ] = "fizzbuzz" }()
                return

            case FIZZ:
                defer func() { buf.A[FIZZ] = "fizz" }()

            case BUZZ:
                defer func() { buf.A[BUZZ] = "buzz" }()

            case NOTFIZZBUZZ:
                defer func() { buf.A[NOTFIZZBUZZ] = "-" }()
                return
            }

        case <-ctx.Done():
            defer func() { buf.T = time.Now().Format(time.StampNano) }()
            return
        }
    }
}

var max = flag.Int("m", 100000, "send numbers")

func main() {
    flag.Parse()

    term, n := set()
    go circle(term, n)

    for i := 0; i < *max; i++ {
        req <- i
    }

    time.Sleep(time.Second)
}