你可以做30行Go? 你可以创build一个有用的,完整的程序来演示它的function吗?

所以,最近几天的热门话题是Go ,来自Google的新语言。 假设你像我一样都是痴迷于编程语言的爱好者,那么你已经下载了它,创build了它并运行你的“Hello,世界”程序(使用UTF-8发明者编写的语言是不是很好? 。 你们都读过教程 , Effective Go和其他一些文档。

现在,你打算怎么做?

我希望看到一些展示Gofunction的演示。 你可以在一个简短的程序中做什么? 展示你最好的例子代码。 尽pipe在一个需求不断变化的项目过程中,你们已经和许多程序员团队一起编写并维护了一个庞大的代码库,但真正衡量一门语言是不可能实现的,只要有限的数量代码确实有助于展示语言的expression力量。 我希望看到能够真正实现Go的独特新function的简短,完整的程序; 不只是片段或“你好,世界”。

所以,发布一些你用Go写的很酷的代码。 利用其独特的function,比如它的goroutines和并发通道,或者基于接口的types系统。 你可以写一个原始的聊天服务器,或凉爽的IRC机器人? 实现可扩展到多个内核的并行Mandelbrot集合? 写一些小语言的翻译? 你能用三十行完成吗?

我select了30个,就像你可以放入堆栈溢出代码块一样,没有溢出,并得到一个滚动条; 应该足够做一些有趣的事情,而不要打高尔夫球,但要足够短,让每个人的注意力快速演示。 例如,只需要重新格式化一下,示例Web服务器应该能够适应(不包括数据)。

向我们展示您的Go代码!

这使得时钟面上的PNG(标准输出)显示当前时间。 它几乎没有打高尔夫球,以适应三十行,所以代码是不是很干净,应该是。

package main import ("image"; "image/png"; "math"; "bufio"; "os"; "time") const clock_size = 200; const radius = clock_size / 3; var colour image.RGBAColor; func circle (clock *image.RGBA) { for angle := float64(0); angle < 360; angle++ { radian_angle := math.Pi * 2 * angle / 360; x := radius * math.Sin (radian_angle) + clock_size/2; y := radius * math.Cos (radian_angle) + clock_size/2; clock.Set (int (x), int (y), colour);}} func hand (clock *image.RGBA, angle float64, length float64) { radian_angle := math.Pi * 2 * angle; x_inc := math.Sin (radian_angle); y_inc := -math.Cos (radian_angle); for i := float64(0); i < length; i++ { x := i * x_inc + clock_size/2; y := i * y_inc + clock_size/2; clock.Set (int (x), int (y), colour);}} func main () { clock := image.NewRGBA (clock_size, clock_size); colour.A = 255; circle (clock); time := time.LocalTime (); hand (clock, (float64(time.Hour) + float64(time.Minute)/60)/12, radius*0.6); // hour hand hand (clock, (float64(time.Minute) + float64(time.Second)/60)/60, radius*0.8); // minute hand out := bufio.NewWriter(os.Stdout); defer out.Flush(); png.Encode(out, clock); } 

像运行一样

 8.out> clock.png

注意到所有这些float64转换? 我从来没有见过类似Go的严格语言。


这是与go fix (和一些手动调整)固定相同的代码,然后使用go fmt自动格式化。 一些换行手动插入。

 package main import ( "bufio" "image" "image/color" "image/png" "math" "os" "time" ) const clock_size = 200 const radius = clock_size / 3 var colour color.RGBA func circle(clock *image.RGBA) { for angle := float64(0); angle < 360; angle++ { radian_angle := math.Pi * 2 * angle / 360 x := radius*math.Sin(radian_angle) + clock_size/2 y := radius*math.Cos(radian_angle) + clock_size/2 clock.Set(int(x), int(y), colour) } } func hand(clock *image.RGBA, angle float64, length float64) { radian_angle := math.Pi * 2 * angle x_inc := math.Sin(radian_angle) y_inc := -math.Cos(radian_angle) for i := float64(0); i < length; i++ { x := i*x_inc + clock_size/2 y := i*y_inc + clock_size/2 clock.Set(int(x), int(y), colour) } } func main() { clock := image.NewRGBA(image.Rect(0, 0, clock_size, clock_size)) colour.A = 255 circle(clock) time := time.Now() hand(clock, (float64(time.Hour())+float64(time.Minute())/60)/12, radius*0.6) // hour hand hand(clock, (float64(time.Minute())+float64(time.Second())/60)/60, radius*0.8) // minute hand out := bufio.NewWriter(os.Stdout) defer out.Flush() png.Encode(out, clock) } 

这是我写的一个Web代理,用于提供对需要HTTP基本身份validation的Web服务的未经身份validation的访问。 我需要一个内部的东西(仍然使用它):

 package main import ( "flag" "log" "net/http" "net/url" ) var target = flag.String("target", "http://www.google.com/", "Where to go.") var addr = flag.String("listen", ":12345", "Address/port on which to listen.") var auth = flag.String("auth", "", "Authorization header to add (optional).") func main() { flag.Parse() targetUrl, uerr := url.Parse(*target) if uerr != nil { log.Fatalf("Error parsing target ``%s'': ", target, uerr.String()) } proxy := http.ReverseProxy{Director: func(req *http.Request) { req.URL.Scheme = targetUrl.Scheme req.URL.Host = targetUrl.Host req.Host = targetUrl.Host if *auth != "" { req.Header.Set("Authorization", *auth) } }} log.Fatal(http.ListenAndServe(*addr, &proxy)) } 

好吧,我会把球打滚。 这是我的第一个Go程序。 这是一个非常原始的聊天服务器,如果我把它压缩一下,可以容纳30行80个字符; 用gofmt格式化,是60行。 它监听一个硬编码的端口(4242),基本上没有error handling,并且不处理客户端断开,除非停止尝试从客户端读取错误。

 package main import ("net";"container/vector";"bufio";"strings") type client struct { conn net.Conn; send chan string; receive chan string } func main() { if listener, err := net.Listen("tcp", "0.0.0.0:4242"); err == nil { master := make(chan string, 100); clients := vector.New(0); go runServer(master, clients); for { if conn, err := listener.Accept(); err == nil { c := client{ conn, master, make(chan string, 100) }; clients.Push(c); go runClient(c); } else { break } } } } func runServer(master chan string, clients *vector.Vector) { for { message := <-master; clients.Do(func (c interface{}) { c.(client).receive <- message }); } } func runClient(c client) { input := make(chan string, 10); go readLines(c, input); for { select { case inMessage := <-input: c.send <- inMessage; case outMessage := <-c.receive: c.conn.Write(strings.Bytes(outMessage)); } } } func readLines(c client, input chan string) { reader := bufio.NewReader(c.conn); for { if line, err := reader.ReadString('\n'); err == nil { input <- line; } else { break } } } 

build立并运行:

  $ 6g server.go
 $ 6l -o服务器server.6
 $ ./server

然后在其他几个terminal上连接

  $ nc localhost 4242 

我真的很喜欢去渠道和select陈述,所以这里有一些东西表明“在一定的时间内去尽可能多的东西”这个概念是很容易的。

这将在300毫秒内生成尽可能多的随机数,并返回当时生成的最大随机数。

 package main import ( "fmt" "math/rand" "time" ) func main() { timeout := time.After(300 * time.Millisecond) numbers := make(chan int) // This channel will be used var numberCount int = 0 var maxNumber int = 0 // Start putting random numbers on the numbers channel go func() { for { numbers <- rand.Int() } }() for { select { case <- timeout: fmt.Printf("%v numbers generated. Max number found: %v.\n", numberCount, maxNumber) return case number := <- numbers: numberCount++ if number > maxNumber { maxNumber = number } } } } 

我从某处复制这个。 相当简单,但显示了一些function。

 package main import ("fmt"; "os" ;"bufio";"io") func main() { if len(os.Args) < 2 { fmt.Printf("usage: catfile \n") } else if pFile, err := os.OpenFile(os.Args[1], os.O_RDONLY, 0); err != nil { fmt.Printf("error opening file : %s\n", err) } else { defer pFile.Close() displayFile(pFile) } } func displayFile(pFile *os.File) { oReader := bufio.NewReader(pFile); for { if sLine, err := oReader.ReadString('\n'); err == nil { fmt.Printf("%s", sLine) } else { if err != io.EOF {fmt.Printf("error reading file : %s\n", err)} break } } }