英文:
What can you do in 30 lines of Go? Can you create a useful, complete program that demonstrates its features?
问题
所以,最近几天的大热话题是Go,这是Google推出的一种新语言。假设你们都像我一样是痴迷于编程语言的极客,你们都已经下载、构建并运行了你们的“Hello, 世界”程序(使用由UTF-8发明者编写的语言真是太好了,不是吗?)。你们都已经阅读了教程、Effective Go和其他一些文档。
那么,你们打算用它做什么呢?
我想看到一些展示Go语言强大功能的演示。在一个简短的程序中,你能做些什么呢?展示你最好的示例代码。虽然真正评估一种语言的价值需要在一个项目的不断变化的需求下,由一个由许多程序员组成的团队编写和维护一个大型代码库,但是在有限的代码量中展示出你能做多少确实有助于展示一种语言的表达能力。我想看到真正利用Go的独特新功能的简短完整程序;不仅仅是片段或“Hello, World”。
所以,请发布一些你用Go编写的酷炫代码。充分利用它的独特功能,如并发的goroutines和channels,或者基于接口的类型系统。你能写一个原始的聊天服务器,或者酷炫的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!
答案1
得分: 12
这是我编写的一个网络代理,用于提供对需要HTTP基本身份验证的网络服务的无需身份验证的访问。我需要它用于内部事务(并且仍在使用):
package main
import (
"flag"
"log"
"net/http"
"net/url"
)
var target = flag.String("target", "http://www.google.com/", "要访问的地址。")
var addr = flag.String("listen", ":12345", "要监听的地址/端口。")
var auth = flag.String("auth", "", "要添加的授权头(可选)。")
func main() {
flag.Parse()
targetUrl, uerr := url.Parse(*target)
if uerr != nil {
log.Fatalf("解析目标地址``%s''时出错: %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))
}
答案2
得分: 8
这是一个生成当前时间的时钟面的PNG图像(输出到stdout)的代码。为了适应30行的限制,代码并不是非常简洁。
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
<pre>
8.out > clock.png
</pre>
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)
}
答案3
得分: 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
英文:
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:
<pre>$ 6g server.go
$ 6l -o server server.6
$ ./server
</pre>
And then in a few other terminals, connect with
<pre>$ nc localhost 4242
</pre>
答案4
得分: 4
我真的很喜欢Go语言的通道和select
语句,所以这里有一个示例,展示了如何轻松表达“在一定时间内尽可能获取多个东西”的概念。
在300毫秒内生成尽可能多的随机数,并返回在此期间生成的最大数。
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
timeout := time.After(300 * time.Millisecond)
numbers := make(chan int) // 这个通道将被使用
var numberCount int = 0
var maxNumber int = 0
// 开始将随机数放入numbers通道
go func() {
for {
numbers <- rand.Int()
}
}()
for {
select {
case <- timeout:
fmt.Printf("%v个数已生成。找到的最大数:%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
}
}
}
}
答案5
得分: -1
我从某个地方复制了这个代码。相当简单,但展示了一些特性。
package main
import ("fmt"; "os" ;"bufio";"io")
func main() {
if len(os.Args) < 2 {
fmt.Printf("用法: catfile \n")
} else if pFile, err := os.OpenFile(os.Args[1], os.O_RDONLY, 0); err != nil {
fmt.Printf("打开文件错误: %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("读取文件错误: %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
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论