Skip to content

Instantly share code, notes, and snippets.

@ccdle12
Last active October 18, 2019 11:35
Show Gist options
  • Save ccdle12/836d4e9c5596145f3759d95009445e5e to your computer and use it in GitHub Desktop.
Save ccdle12/836d4e9c5596145f3759d95009445e5e to your computer and use it in GitHub Desktop.

Golang Cheat Sheet

Covers different areas of programming and the best practices/components explained.

Basic Types

bool

string

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

byte // alias for uint8

rune // alias for int32
     // represents a Unicode code point

float32 float64

complex64 complex128

Conversions

someNum := x
someFloat := float32(x)

Concurrency

Channels

A way to communicate between different go routines.

someChan := make(chan bool)

Send to a channel:

go func() {
  someChan <- true
}

Read from a channel:

msg := <- someChan
fmt.Print(msg)

Range

For Select

A pattern that blocks a programming from ending by using for{}

Allows multiple channels to be read-from using select{}.

Each case reads from a channel and handles the message.

for {
        select {
        case criticalMsg := <-criticalAlert:
            log.Printf("Critical alert received!")

            if err := criticalMsg.Ack(false); err != nil {
                log.Fatalf("Failed to acknowledge alert msg")
            }

        case rateLimitMsg := <-rateLimitAlert:
            log.Printf("Rate limit alert received!")

            if err := rateLimitMsg.Ack(false); err != nil {
                log.Fatalf("Failed to acknowledge alert msg")
            }

        }
    }

Encoding

JSON

Encoding and Decoding JSON to structs in go is quite straight forward.

Marshalling struct -> json.

import (
  "encoding/json"
)

type Image struct {
  ImageId   string
  UserId    string
  ImagePath string
}

image := &Image{
  ImageId:   "some-image",
  UserId:    "some-user",
  ImagePath: "some-path",
}

msg, err := json.Marshal(image)
if err != nil {
  log.Fatalf("Failed to marshal image to json.")
}

File System

File system can be handled by different packages. For now I'm using the os package.

Creating a file

import "os"

file, err := os.Create("file.txt")
if err != nil {
  ...
}
defer file.Close()

Init Function

First function that is run in a program, runs before main().

package main

import(...)

func init() {
...do stuff...
}

func main() {
... do stuff after init...
}

GRPC

Assumes:

  • a proto file exists

Setup a GRPC Server

  1. Use the protoc compiler to generate the golang files.
protoc -I ./ some-file.proto --go_out=plugins=grpc:.
  1. Import the generated grpc files and use them to create a GRPC Server as follows:
package gatewayserver

import (
    proto "github.com/simplebank/orders_service/grpc"
    "golang.org/x/net/context"
)

// Server is the implementation struct for the proto file describing the endpoints
// callable from the api_gateway service.
type Server struct{}

// CreateOrder handles a request from the api_gateway to place an order on the
// market.
func (s *Server) CreateOrder(context.Context, *proto.OrderRequest) (*proto.OrderResponse, error) {
    return &proto.OrderResponse{Status: "Order Placed"}, nil
}

// GetAllOrders returns a list of all orders for a particular user.
func (s *Server) GetAllOrders(context.Context, *proto.OrderStatusAllRequest) (*proto.OrderStatusAllResponse, error) {
    orderStatusResponse := &proto.OrderStatusResponse{
        OrderId: "1",
        UserId:  "1",
        Symbol:  "BTC",
        Amount:  134,
        Status:  "Pending",
    }
    allResponses := []*proto.OrderStatusResponse{orderStatusResponse}

    return &proto.OrderStatusAllResponse{Orders: allResponses}, nil
}

OS

env

Getting env variables.

import "os"

os.Getenv("SOME_ENV")

Logging

Currently using logrus.

The below code example shows the current practice on setting up a custom log format with logrus to match a projects logging filter (logstash).

package main

import (
    "fmt"
    log "github.com/sirupsen/logrus"
    "os"
    "strings"
)

// Global logger used for logging in this service.
var logger *log.Logger

// Wraps the log.TextFormatter struct but uses a custom Format function according
// to the projects logstash filter.
type logStashFormatter struct {
    log.TextFormatter
}

// Format uses a custom implementation to match the logstash filter.
// Custom format: `time - name_of_service - log_level - message`.
// TODO (ccdle12): pull service name from environment.
func (l *logStashFormatter) Format(entry *log.Entry) ([]byte, error) {
    return []byte(
        fmt.Sprintf("%s - fees_service - %s - %s",
            entry.Time.Format(l.TimestampFormat),
            strings.ToUpper(entry.Level.String()),
            entry.Message),
    ), nil
}

// Entry point, initializes the global logger variable with the custom formatter.
func init() {
    logger = &log.Logger{
        Out:   os.Stdout,
        Level: log.DebugLevel,
        Formatter: &logStashFormatter{log.TextFormatter{
            TimestampFormat: "2006-01-02 15:04:05",
            FullTimestamp:   true},
        },
    }
}

Net

Creating a TCP Server

Creates a TCP server, creates a TCP server that implements the Listener interface.

import "net"

listener, err := net.Listen("tcp", "0.0.0.0:5000")
if err != nil {
  log.Fatalf("failed")
}

Structs

type SomeStruct struct {
  *fields*
}

Methods

Methods for structs are identified by:

type Something struct {...}

func (s *Something) someMethod() float32 {}

Slices

someSlice := []string{"Hello", "World"}
someSlice = append(someSlice, "!")

Testing

In golang test files should have the following format:

something_test.go

To run tests in test folder:

$ go test

Example test file:

  • Imports the testing package: "testing"
  • Test functions start with prefix TestSomething(t *testing.T)
  • Test functions declared in the parameter of the function (t *testing.T)
  • Test assertions if something != expected { t.Errorf(some_message)}. Errorf will cause a failed test.
package main

import (
    "testing"
)

func TestCalcPrice(t *testing.T) {
    something := &Something{Quantity: 5, Price: 6}

    expected := float32(29.400002)
    if something.CalcPrice() != expected {
        t.Errorf("expected: %v received: %v", expected, something.CalcPrice())
    }
}

Testing in alpine

Alpine containers do not have gcc.

When running tests we need to run as :

go test -v -vet=off ./folder-path/...

Time

Sleep

import "time"

time.Sleep(5 * time.Second)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment