Что вы можете сделать в 30 строках Go? Можете ли вы создать полезную, полную программу, демонстрирующую ее функции?
Итак, большой шум в последние несколько дней - это Go, новый язык от Google. Предполагая, что вы все навязчивые программисты, такие как я, вы все загрузили, построили и запустили программу "Hello, 世界" (разве не приятно использовать язык, написанный изобретателями UTF-8?), Вы все прочитали учебник, Эффективный путь, и некоторые из других документов.
Теперь, что вы собираетесь с ним делать?
Я бы хотел увидеть некоторые демоверсии, которые хвастаются силой Go. Что вы можете сделать в краткой программе? Покажите свой лучший примерный код. В то время как истинная мера языка не может быть решена до тех пор, пока вы не написали и не сохранили большую базу кода с командой многих программистов в ходе проекта с меняющимися требованиями, видя, сколько вы можете сделать в ограниченном количестве код помогает продемонстрировать выразительную силу языка. Я хотел бы видеть короткие, полные программы, которые действительно используют уникальные новые возможности Go; а не только фрагменты или "Привет, мир".
Итак, напишите какой-нибудь классный код, который вы написали с Go. Воспользуйтесь его уникальными функциями, такими как его goroutines и каналы для concurrency, или его система на основе интерфейса. Можете ли вы написать примитивный чат-сервер или охладить IRC-бот? Внедрить параллельный набор Мандельброта, который масштабируется по многим ядрам? Напишите переводчика для небольшого языка? И можете ли вы сделать все это в 30 строках?
Я выбрал 30 произвольно примерно столько же, сколько вы можете поместиться в блок кода без его переполнения и получения полосы прокрутки; это должно быть достаточно, чтобы сделать что-то интересное без игры в гольф слишком много, но достаточно короткое, чтобы держать все внимание для быстрой демонстрации. Например, при небольшом переформатировании пример веб-сервер должен соответствовать (не считая данных).
Покажите нам свой код Go!
Ответы
Ответ 1
Это делает 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 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
Это веб-прокси, который я написал, чтобы предоставить неавторизованный доступ к веб-службе, для которой требуется базовая аутентификация HTTP. Мне нужно было это для внутренней вещи (и по-прежнему использовать его):
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))
}
Ответ 3
Хорошо, я верну мяч. Вот моя первая программа 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
Ответ 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
}
}
}
}
Ответ 5
Я скопировал это откуда-то. Довольно просто, но показывает некоторые особенности.
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
}
}
}