Cheat Sheet
My personal cheat sheet for golang
Naming Convention
Thanks to: https://medium.com/@kdnotes/golang-naming-rules-and-conventions-8efeecd23b68
Files
Go follows a convention where source files are all lower case with underscore separating multiple words.
Compound file names are separated with _
File names that begin with “.” or “_” are ignored by the go tool
Files with the suffix
_test.go
are only compiled and run by thego test
tool.
Functions
The case defines if it will be public or private for the package.
Private:
func writeToDb(){}
Public:
func WriteToDb(){}
The same for struct properties
.
Constants
Constant should use all capital letters and use underscore _
to separate words.
Ex: const CONNECTION_URL := "...."
Variables
Generally, use a relatively simple (short) name.
Consistent naming style should be used the entire source code
user
to u
userID
to uid
If variable type is
bool
, its name should start withHas
,Is
,Can
orAllow
, etc.A single letter represents index:
i, j, k
Variables
// DECLARATIONS
var name string
name = "Thor"
name := "Thor"
// ARRAYS
var numbers [3]int
numbers[0] = 1
// SLICES
numbers := []int{}
numbers = append(numbers, 2)
IF
name := "thor"
if name == "thor" {
} else if name == "odin" {
} else {
}
FOR
names := []string{
"Thor", "Odin", "Loki",
}
for i := 0; i < len(names); i++ {
fmt.Println(i, ":", names[i])
}
for i, v := range names {
fmt.Println(i, ":", v)
}
SWITCH
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS X.")
case "linux":
fmt.Println("Linux.")
default:
// freebsd, openbsd,
// plan9, windows...
fmt.Printf("%s.\n", os)
}
FUNCTION
func simple() {
fmt.Println("simple function")
}
func withReturnValue() string {
return "Function with return value"
}
func withArgs(myArg string) {
fmt.Println(myArg)
}
func withMultipleArgs(myList ...string) {
// withMultipleArgs("Val1", "Val2", "ValN")
}
func withToupleResult() (value int, err error) {
// value, err = withToupleResult()
return 1, nil
}
// FUNCTION AS PARAMETER
type Fn func()
func onError(handler Fn) {
handler()
}
Folders
package main
import (
"log"
"os"
)
func main() {
// Create a folder/directory at a full qualified path
err := os.Mkdir("/Users/temp", 0755)
if err != nil {
log.Fatal(err)
}
// Create a folder recursively
err := os.MkdirAll(dirPath, 0755)
if err != nil {
log.Fatal(err)
}
// Get current dir
currentDirPath, err := os.Getwd()
}
Read File
content, _ := ioutil.ReadFile("list.txt")
fmt.Println(string(content))
Write File
fileName := "new-file.txt"
flags := os.O_WRONLY | os.O_CREATE | os.O_APPEND
file, _ := os.OpenFile(fileName, flags, 0666)
file.WriteString("This is a new file")
file.Close()
Error Handling
package main
import (
"bufio"
"fmt"
"io"
"os"
"strings"
)
func main() {
fileName := "list.txt"
file, err := os.Open(fileName)
handleError(err)
reader := bufio.NewReader(file)
var lines []string
closeFile := func() {
file.Close()
}
for {
line, err := reader.ReadString('\n')
if err == io.EOF {
closeFile()
break
}
handleErrorWithCallback(err, closeFile)
line = strings.TrimSpace(line)
lines = append(lines, line)
}
fmt.Println(lines)
}
type ErrorHandlerCallback func()
func handleError(err error) {
if err != nil {
panic(err)
}
}
func handleErrorWithCallback(err error, handler ErrorHandlerCallback) {
if err != nil {
handler()
panic(err)
}
}
Date and Time
Time Format: https://golang.org/src/time/format.go
package main
import (
"fmt"
"time"
)
func main() {
// dd/mm/yyyy hh:mm:ss
now := time.Now().Format("02/01/2006 15:04:05")
fmt.Println(now)
}
Structs
type User struct {
email string
password string
enabled bool
}
// adding a Disable function to a user instance
func (u *User) Disable() {
u.enabled = false
}
func main() {
admin := User{
email: "admin@admin.com",
password: "Admin123",
enabled: true,
}
guest := new(User)
guest.email = "guest@guest.com"
}
Creating Packages
//
// playground/user/user.go
//
package user
type User struct {
Email string
Password string
Enabled bool
}
func (u *User) Disable() {
u.Enabled = false
}
//
// playground/main.go
//
package main
import (
"fmt"
"playground/user"
)
func main() {
admin := user.User{
Email: "admin@admin.com",
Password: "Admin123",
Enabled: true,
}
fmt.Println(admin)
}
Pointers
// CODE SAMPLE
package main
import "fmt"
func main() {
user := User{Enabled: true}
fmt.Println(user)
disableUser(user)
fmt.Println(user)
}
type User struct {
Enabled bool
}
func disableUser(user User) {
user.Enabled = false
}
// OUTPUT
{true}
{true}
/*
This will not change the user because the function
disableUser is recieving a user as a value, not
a pointer to the same user in memory.
To change the original object, we need do two things:
1. Change the function to receive a pointer.
2. Call the function sending the pointer.
And here is the magic words:
- Use * to receive a pointer
- Use & to send a pointer
*/
func main() {
user := User{Enabled: true}
fmt.Println(user)
disableUser(&user) // <=== HERE
fmt.Println(user)
}
type User struct {
Enabled bool
}
func disableUser(user *User /* <=== HERE*/) {
user.Enabled = false
}
// OUTPUT NOW
{true}
{false}
Interfaces
func main() {
user := User{Status: ACTIVE}
fmt.Println(user)
setStatus(&user, INACTIVE)
fmt.Println(user)
}
type Status int
const (
ACTIVE Status = iota
INACTIVE
DELETED
)
/*
An interface define all methods an struct needs to
implement to be compliance with the definition.
*/
type WithStatus interface {
SetStatus(status Status)
}
func setStatus(entity WithStatus, status Status) {
entity.SetStatus(status)
}
/*
If we want to pass a user instance to the setStatus func,
the User struct must implement all the methods the
WithStatus interface require.
*/
type User struct {
Status Status
}
func (user *User) SetStatus(status Status) {
user.Status = status
}
Enum
type Status int
const (
ACTIVE Status = iota
INACTIVE
DELETED
)
WaitGroup
/*
When the application runs multiple functions
in background, if you want to deal with the
concurrence and know when is finish, use the
WaitGroup from sync package.
*/
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup // create the group
func main() {
wg.Add(1) // indicating a new work will be add
go say("Hi")
wg.Wait() // wait until all the work done
}
func say(text string) {
fmt.Printf(text)
wg.Done() // mark a work for done
}
Defer
/*
When we want to run something after the function finishes
(even for an error, for example), we can use defer.
*/
package main
import (
"fmt"
)
func main() {
defer finish()
fmt.Println("Enf of main")
}
func finish() {
fmt.Println("We are done!")
}
/*
=== OUTPUT ===
Enf of main
We are done!
*/
Panic and Recover
/*
When something goes wrong and a panic is raise,
has a function that you can call and prevent the
software to stop work.
Its called recover.
*/
package main
import (
"fmt"
)
func main() {
defer finish()
defer cleanup()
fmt.Println("Enf of main")
panic("fuuuuuuck") // <=== it should kill the program, right?
}
func cleanup() {
if r := recover(); r != nil { // <=== but here we are recovering =)
fmt.Println("recover: ", r)
}
}
func finish() {
fmt.Println("We are done!")
}
Channels and Concurrency
Channels are the pipes that connect concurrent goroutines. You can send values into channels from one goroutine and receive those values into another goroutine.
Youtube:
package main
import (
"fmt"
)
func main() {
channel := make(chan int)
go sum(channel, 5, 8)
result := <-channel
close(channel) // close the channel after no more work needed
fmt.Println(result)
}
func sum(c chan int, a int, b int) {
c <- a + b
}
Unit Test
// my_file_test.go
package my_package
import "testing"
func TestCrawler(t *testing.T) {
result := my_func()
if result == nil {
t.Error("Ooops! This is the error message") // to indicate test failed
}
}
Last updated
Was this helpful?