Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What can you do in 30 lines of Go? Can you create a useful, complete program that demonstrates its features? [closed]

Tags:

go

demo

People also ask

How do you comment a function in Golang?

You can create block comments two ways in Go. The first is by using a set of double forward slashes and repeating them for every line. The second is to use opening tags ( /* ) and closing tags ( */ ). For documenting code, it is considered idiomatic to always use // syntax.


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

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

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 

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