Go 1.1 達到類似 Python 的 map 及 list comprehension

Posted by tjwei on 星期四, 4月 25, 2013 with No comments

Go 1.1 的 reflect 新增了 SliceOf, ChanOf,以及 MakeFunc。
SliceOf 及 ChanOf 可以達到類似於 Python 裡面的 list 及 iterator 的功能,MakeFunc 可以搭配 Call 使用,達到類似 decorator 的功能。
以下是簡單測試了一下 Python 的 map 及類似 list comprehension 的效果。


package main
import (
"fmt"
"reflect"
)
type duck interface{}
// Python like map function
func Map(fn duck, list duck) duck {
fnType, fnValue := reflect.TypeOf(fn), reflect.ValueOf(fn)
listValue := reflect.ValueOf(list)
// fmt.Println("assert", fnType.NumOut() == 1, fnType.NumIn() == 1, fnType.In(0) == listType.Elem())
rtnType := reflect.SliceOf(fnType.Out(0))
rtnValue := reflect.MakeSlice(rtnType, 0, listValue.Len())
for i := 0; i < listValue.Len(); i++ {
in := []reflect.Value{listValue.Index(i)}
rtnValue = reflect.Append(rtnValue, fnValue.Call(in)[0])
}
return rtnValue.Interface()
}
// Python like range function
func Range(n int) []int {
rtn := make([]int, 0, n)
for i := 0; i < n; i++ {
rtn = append(rtn, i)
}
return rtn
}
type in chan duck
// Python like list comprehension construction
func List(fn func(x in)) duck {
x := make(chan duck)
go func() { fn(x); close(x) }()
first := <-x
rtnType := reflect.SliceOf(reflect.TypeOf(first))
rtnValue := reflect.MakeSlice(rtnType, 0, 0)
rtnValue = reflect.Append(rtnValue, reflect.ValueOf(first))
for v := range x {
rtnValue = reflect.Append(rtnValue, reflect.ValueOf(v))
}
return rtnValue.Interface()
}
func main() {
fn := func(x int) string { return fmt.Sprintf("%dx%d=%d", x, x, x*x) }
// Compare to rtn = map(fn, range(10))
rtn := Map(fn, Range(10)).([]string)
fmt.Println(rtn)
// Compare to rtn2 = [ i * i for i in range(5)]
rtn2 := List(func(x in) {for i := 0; i < 5; i++ { x <- i * i }}).([]int)
fmt.Println(rtn2)
}
view raw gistfile1.go hosted with ❤ by GitHub
Categories: , ,