你可以在30行Go中做些什么?你能创建一个有用的,完整的程序来展示它的功能吗?

时间:2009-11-14 18:07:01

标签: go demo

所以,过去几天的热门话题是来自Google的新语言Go。假设你是所有迷恋程序设计语言的极客,就像我一样,你已经全部下载,构建它,并运行你的“Hello,世界”程序(使用UTF-8发明者编写的语言不是很好吗?) 。您已经阅读了the tutorialEffective Go和其他一些文档。

现在,你打算用它做什么?

我想看一些炫耀Go的力量的演示。你能在简短的节目中做些什么?展示你最好的示例代码。虽然在你需要不断变化的项目过程中与许多程序员组成的团队编写并维护一个大型代码库之后,才能真正衡量一种语言的真正衡量标准,看看你能在有限数量的情况下做多少工作。代码确实有助于展示语言的表达能力。我希望看到简短,完整的程序,真正体现Go的独特新功能;不只是片段或“Hello,World”。

所以,发布一些你用Go写的很酷的代码。利用其独特的功能,如goroutines和并发通道,或基于接口的类型系统。你能写一个原始的聊天服务器,还是很酷的IRC机器人?实现可扩展到多个核心的并行Mandelbrot集?为一些小语言写一个翻译?你能用30行做到这一切吗?

我任意选择30,就像你可以装入Stack Overflow代码块一样,没有溢出并获得滚动条;它应该足够做一些有趣的事情,不要打太多高尔夫球,但要足够短,以便让每个人都注意快速演示。例如,只需稍微重新格式化,示例web server应该能够适合(不计算数据)。

向我们展示您的Go代码!

5 个答案:

答案 0 :(得分:12)

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

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))
}

答案 1 :(得分:8)

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

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)
}

答案 2 :(得分:4)

好的,我会让球滚动。这是我的第一个Go程序。它是一个非常原始的聊天服务器,如果我将它压缩一下,它可以容纳30行80个字符;格式为gofmt,为60行。它侦听硬编码端口(4242),基本上没有错误处理,并且除了在客户端遇到错误时停止尝试从客户端读取时,不处理客户端断开连接。

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 } } }

构建并运行:

$ 6g server.go
$ 6l -o server server.6
$ ./server

然后在其他几个终端中,连接

$ nc localhost 4242 

答案 3 :(得分:4)

我非常喜欢go的频道和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
      }
    }
  }
}

答案 4 :(得分:0)

我从某个地方复制了这个。相当简单,但显示了一些功能。

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
        } 
        }
}