Skip to content

Instantly share code, notes, and snippets.

@icecrime
Last active November 7, 2023 08:38
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save icecrime/67399480c9a10b48fadc to your computer and use it in GitHub Desktop.
Save icecrime/67399480c9a10b48fadc to your computer and use it in GitHub Desktop.
An experiment with Golang reflection and channels
package main
import (
"reflect"
"strings"
)
func makeChannel(t reflect.Type, chanDir reflect.ChanDir, buffer int) reflect.Value {
ctype := reflect.ChanOf(chanDir, t)
return reflect.MakeChan(ctype, buffer)
}
type T interface{}
type Query struct {
input reflect.Value
}
func (q *Query) Apply(f T) *Query {
value := reflect.ValueOf(f)
if value.Kind() != reflect.Func {
panic("Apply() parameter must be a function")
}
rtype := value.Type().Out(0)
output := makeChannel(rtype, reflect.BothDir, 0)
go func() {
var elem reflect.Value
for ok := true; ok; {
if elem, ok = q.input.Recv(); ok {
result := value.Call([]reflect.Value{elem})
output.Send(result[0])
}
}
output.Close()
}()
return &Query{output}
}
func From(array T) *Query {
value := reflect.ValueOf(array)
if value.Kind() != reflect.Slice {
panic("From() parameter must be a slice")
}
etype := value.Type().Elem()
output := makeChannel(etype, reflect.BothDir, 0)
go func() {
for i := 0; i != value.Len(); i++ {
output.Send(value.Index(i))
}
output.Close()
}()
return &Query{output}
}
func (q *Query) Items() <-chan T {
output := make(chan T)
go func() {
for ok := true; ok; {
var elem reflect.Value
if elem, ok = q.input.Recv(); ok {
output <- elem.Interface()
}
}
close(output)
}()
return output
}
func (q *Query) StringItems() <-chan string {
output := make(chan string)
go func() {
for elem := range q.Items() {
output <- elem.(string)
}
close(output)
}()
return output
}
func main() {
t := []int{0, 1, 2}
m := map[int]string{0: "zero", 1: "one", 2: "two"}
for elem := range From(t).Apply(func(x int) string { return m[x] }).Apply(strings.ToUpper).StringItems() {
println(elem)
}
}
@icecrime
Copy link
Author

icecrime commented May 9, 2014

$ go run main.go
ZERO
ONE
TWO

@lpgc
Copy link

lpgc commented Oct 31, 2018

very nicely done ... good example of "reflect" and channels, thanks!

@9iang22
Copy link

9iang22 commented Feb 14, 2023

thanks! it helps me a lot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment