30 行 Go 能做什么?您能创建一个有用的、完整的程序来展示其功能吗?

发布于 2024-08-11 07:52:17 字数 971 浏览 10 评论 0原文

因此,过去几天的热门话题是 Google 的新语言 Go。假设你们都是像我一样痴迷的编程语言极客,你们都下载了它,构建了它,并运行了您的“Hello,世界”程序(使用 UTF-8 发明者编写的语言不是很好吗?) 。你们都已阅读教程Effective Go,以及其他一些文档。

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

我想看一些展示 Go 强大功能的演示。在一个简短的程序中你能做什么?展示您最好的示例代码。虽然只有在需求不断变化的项目过程中与一个由许多程序员组成的团队一起编写和维护一个大型代码库,才能真正衡量一门语言的真正程度,看看你能在有限的时间内完成多少工作代码确实有助于展示语言的表达能力。我希望看到简短而完整的程序,能够真正发挥 Go 独特的新功能;不仅仅是片段或“你好,世界”。

因此,发布一些您用 Go 编写的很酷的代码。利用其独特的功能,例如它的 goroutine 和并发通道,或其基于接口的类型系统。你能编写一个原始的聊天服务器,或者很酷的 IRC 机器人吗?实现可扩展到多个核心的并行 Mandelbrot 集?为某种小语言编写一个解释器?您能用 30 行代码完成所有工作吗?

我任意选择了 30 个,尽可能多地适合 Stack Overflow 代码块,而不会溢出并出现滚动条;它应该足以做一些有趣的事情而无需打太多高尔夫球,但又足够短以吸引每个人的注意力以进行快速演示。例如,只需进行一些重新格式化,示例 Web 服务器 就应该能够适合(不计算数据)。

向我们展示您的 Go 代码!

So, the big buzz in the last few days is Go, the new language from Google. Assuming you're all obsessive programming language geeks like me, you've all downloaded it, built it, and run your "Hello, 世界" program (isn't it nice using a language written by the inventors of UTF-8?). You've all read the tutorial, Effective Go, and some of the other docs.

Now, what are you going to do with it?

I'd like to see some demos that show off the power of Go. What can you do in a brief program? Show off your best example code. While the true measure of a language can't really be taken until you've written and maintained a large codebase with a team of many programmers over the course of a project with changing requirements, seeing how much you can do in a limited amount of code does help to demonstrate the expressive power of a language. I'd like to see short, complete programs that truly exercise the unique new features of Go; not just snippets or "Hello, World".

So, post some cool code you've written with Go. Take advantage of its unique features, like its goroutines and channels for concurrency, or its interface based type system. Can you write a primitive chat server, or cool IRC bot? Implement a parallel Mandelbrot set that scales to many cores? Write an interpreter for some tiny language? And can you do it all in 30 lines?

I chose 30 arbitrarily as about as much as you can fit into a Stack Overflow code block without it overflowing and getting a scroll bar; it should be enough to do something interesting without golfing too much, but short enough to keep everyone's attention for a quick demo. For instance, with just a bit of reformatting, the example web server should be able to fit (not counting the data).

Show us your Go code!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

太阳公公是暖光 2024-08-18 07:52:17

这是我编写的一个 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))
}

This is a web proxy I wrote to provide unauthenticated access to a web service that required HTTP basic auth. I needed it for an internal thingy (and still use it):

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))
}
西瑶 2024-08-18 07:52:17

这使得钟面的 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)
}

This makes a PNG (on stdout) of a clock face showing the current time. It's barely golfed to fit thirty lines, so the code is not quite as clean as it should be.

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

Run it like

8.out > clock.png

Notice all those float64 casts? I've NEVER seen a language as strict as Go about types.


This is the same code fixed with go fix (and some manual tweaking) and then automatically formatted using go fmt. Some newlines where inserted manually.

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)
}
萌辣 2024-08-18 07:52:17

好的,我会开始行动。这是我的第一个 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 

OK, I'll get the ball rolling. Here's my first Go program. It's a very primitive chat server, and fits in 30 lines of 80 characters if I compress it down a bit; formatted with gofmt, it is 60 lines. It listens on a hard coded port (4242), does basically no error handling, and doesn't handle client disconnection other than stopping trying to read from a client if it gets an error.

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 and run with:

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

And then in a few other terminals, connect with

$ nc localhost 4242 

我真的很喜欢 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
      }
    }
  }
}

I really like go's channels and the select statement, so here's something that shows how easy it is to express the "go and get as many things as possible within a certain time" concept.

This generates as many random numbers as possible within 300 milliseconds and returns the biggest one generated in that time.

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
      }
    }
  }
}
再浓的妆也掩不了殇 2024-08-18 07:52:17

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

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

I copied this from somewhere. Fairly simple, but shows some features.

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
        } 
        }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文