したがって、ここ数日の大きな話題は Go 、Googleの新しい言語です。あなたが私のようなすべての強迫的なプログラミング言語オタクであると仮定すると、あなたはそれをダウンロードし、構築し、そしてあなたの「こんにちは、世界」プログラムを実行しました(UTF-8の発明者によって書かれた言語を使用してそれは素晴らしいではありませんか?) 。 チュートリアル 、 Effective Go 、およびその他のドキュメントをすべて読んだことがあります。
さて、あなたはそれをどうするつもりですか?
Goのパワーを披露するデモを見たいのですが。簡単なプログラムで何ができますか?最高のサンプルコードを披露してください。要件が変化するプロジェクトの過程で、多くのプログラマーのチームと一緒に大規模なコードベースを作成して維持し、限られた量でどれだけのことができるかを確認するまで、言語の真の測定は実際には行えません。コードは、言語の表現力を示すのに役立ちます。 Goのユニークな新機能を真に発揮する短くて完全なプログラムが欲しいです。スニペットや「Hello、World」だけではありません。
だから、あなたがGoで書いたいくつかのクールなコードを投稿してください。並行性のためのゴルーチンやチャネル、またはインターフェースベースの型システムなど、その独自の機能を利用してください。原始的なチャットサーバーを書くことはできますか、それともクールなIRCボットですか?多くのコアに拡張できる並列マンデルブロ集合を実装しますか?小さな言語のインタープリターを書きますか?そしてそれをすべて30行で行うことができますか? ?
Stack Overflowコードブロックがオーバーフローしてスクロールバーが表示されることなく、そのブロックに収まる範囲で30を任意に選択しました。ゴルフをしすぎずに何か面白いことをするのに十分なはずですが、簡単なデモのためにみんなの注意を引くのに十分短いはずです。たとえば、少し再フォーマットするだけで、例 web server は適合できるはずです(データはカウントされません)。
Goコードを見せてください!
これにより、現在の時刻を示す文字盤の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 abouttypesほど厳格な言語を見たことがありません。
これは、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)
}
これは、HTTP基本認証を必要とするWebサービスへの認証されていないアクセスを提供するために作成した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))
}
私は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
}
}
}
}
OK、ボールを転がします。これが私の最初のGoプログラムです。これは非常に原始的なチャットサーバーであり、少し圧縮すると80文字の30行に収まります。 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
これをどこかからコピーしました。かなりシンプルですが、いくつかの機能を示しています。
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
}
}
}