Go Cheatsheet
Table of Contents
- Go Cheatsheet
Formatting Verbs
General Formatting Verbs
| Verb | Description |
|---|---|
%v |
is used to print the value of the arguments |
%T |
is used to print the type of the arguments |
%#v |
Prints the value in Go-syntax format |
%+v |
Prints the struct with field names |
func main() {
var i = 15.5
var txt = "Hello World!"
fmt.Printf("%v\n", i)
fmt.Printf("%#v\n", i)
fmt.Printf("%v%%\n", i)
fmt.Printf("%T\n", i)
fmt.Printf("%v\n", txt)
fmt.Printf("%#v\n", txt)
fmt.Printf("%T\n", txt)
}
Outputs:
15.5
15.5
15.5%
float64
Hello World!
"Hello World!"
string
Integer Formatting Verbs
| Verb | Description |
|---|---|
%b |
Base 2 |
%d |
Base 10 |
%+d |
Base 10 and always show sign |
%o |
Base 8 |
%O |
Base 8, with leading 0o |
%x |
Base 16, lowercase |
%X |
Base 16, uppercase |
%#x |
Base 16, with leading 0x |
%4d |
Pad with spaces (width 4, right justified) |
%-4d |
Pad with spaces (width 4, left justified) |
%04d |
Pad with zeroes (width 4) |
func main() {
var i = 15
fmt.Printf("%b\n", i)
fmt.Printf("%d\n", i)
fmt.Printf("%+d\n", i)
fmt.Printf("%o\n", i)
fmt.Printf("%O\n", i)
fmt.Printf("%x\n", i)
fmt.Printf("%X\n", i)
fmt.Printf("%#x\n", i)
fmt.Printf("%4d\n", i)
fmt.Printf("%-4d\n", i)
fmt.Printf("%04d\n", i)
}
1111
15
+15
17
0o17
f
F
0xf
15
15
0015
String Formatting Verbs
| Verb | Description |
|---|---|
%s |
Prints the value as plain string |
%q |
Prints the value as a double-quoted string |
%8s |
Prints the value as plain string (width 8, right justified) |
%-8s |
Prints the value as plain string (width 8, left justified) |
%x |
Prints the value as hex dump of byte values |
% x |
Prints the value as hex dump with spaces |
func main() {
var txt = "Hello"
fmt.Printf("%s\n", txt)
fmt.Printf("%q\n", txt)
fmt.Printf("%8s\n", txt)
fmt.Printf("%-8s\n", txt)
fmt.Printf("%x\n", txt)
fmt.Printf("% x\n", txt)
}
Hello
"Hello"
Hello
Hello
48656c6c6f
48 65 6c 6c 6f
Boolean Formatting Verbs
| Verb | Description |
|---|---|
%t |
Value of the boolean operator in true or false format (same as using %v) |
Float Formatting Verbs
| Verb | Description |
|---|---|
%e |
Scientific notation with ‘e’ as exponent |
%f |
Decimal point, no exponent |
%.2f |
Default width, precision 2 |
%6.2f |
Width 6, precision 2 |
%g |
Exponent as needed, only necessary digits |
func main() {
var i = 3.141
fmt.Printf("%e\n", i)
fmt.Printf("%f\n", i)
fmt.Printf("%.2f\n", i)
fmt.Printf("%6.2f\n", i)
fmt.Printf("%g\n", i)
}
3.141000e+00
3.141000
3.14
3.14
3.141
Arrays
Syntax
var array_name = [length]datatype{values} // here length is defined
var array_name = [...]datatype{values} // here length is inferred
array_name := [length]datatype{values} // here length is defined
Array Initialization
arr1 := [5]int{} //not initialized
arr2 := [5]int{1,2} //partially initialized
arr3 := [5]int{1,2,3,4,5} //fully initialized
arr4 := [5]int{1:10,2:40} // Only Specific Elements
[0 0 0 0 0]
[1 2 0 0 0]
[1 2 3 4 5]
[0 10 40 0 0]
Slices
len() function - returns the length of the slice (the number of elements in the slice)
cap() function - returns the capacity of the slice (the number of elements the slice can grow or shrink to)
Create a Slice
slice_name := []datatype{values}
var myarray = [length]datatype{values} // An array
myslice := myarray[start:end] // A slice made from the array
slice_name := make([]type, length, capacity)
Append
slice_name = append(slice_name, element1, element2, ...)
slice3 = append(slice1, slice2...)
Copy
Takes in two slices dest and src:
copy(dest, src)
Loop
for index, value := array|slice|map {
// code to be executed for each iteration
}
for {
// forever loop
}
Functions
Variadic
// Variadic function to join strings
func joinstr(elements ...string) string {
return strings.Join(elements, "-")
}
Named Return Values
func myFunction(x int, y int) (result int) {
result = x + y
return
}
Multiple Return Values
func myFunction(x int, y string) (result int, txt1 string) {
result = x + x
txt1 = y + " World!"
return
}
Defer functions
multiple defer statements executed in LIFO order. Defer statements are generally used to ensure that the files are closed when their need is over, or to close the channel, or to catch the panics in the program.
defer func (parameter_list) (return_type) {
// code
} (arguments)
// Main function
func main() {
// Calling mul() function
// Here mul function behaves
// like a normal function
mul(23, 45)
// Calling mul()function
// Using defer keyword
// Here the mul() function
// is defer function
defer mul(23, 56)
}
Pass Functions as Value
func compute(fn func(float64, float64) float64) float64 {
return fn(3, 4)
}
func main() {
hypot := func(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
fmt.Println(hypot(5, 12))
fmt.Println(compute(hypot))
fmt.Println(compute(math.Pow))
}
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder()
fmt.Println(pos(i), neg(-2*i))
}
Structure
type struct_name struct {
member1 datatype;
member2 datatype;
member3 datatype;
...
}
var a = struct_name{"Akshay", "PremNagar", "Dehradun", "Uttarakhand", 252636}
Struct Embedding
type base struct {
num int
}
type container struct {
base
str string
}
Method
| Method | Function |
|---|---|
| It contains a receiver. | It does not contain a receiver. |
| Methods of the same name but different types can be defined in the program. | Functions of the same name but different type are not allowed to be defined in the program. |
Struct Type Receiver
// Author structure
type author struct {
name string
branch string
particles int
salary int
}
// Method with a receiver
// of author type
func (a author) show() {
fmt.Println("Author's Name: ", a.name)
fmt.Println("Branch Name: ", a.branch)
fmt.Println("Published articles: ", a.particles)
fmt.Println("Salary: ", a.salary)
}
// Main function
func main() {
res := author{
name: "Sona",
branch: "CSE",
particles: 203,
salary: 34000,
}
// Calling the method
res.show()
}
Non-Struct Type Receiver
// Type definition
type data int
// Defining a method with
// non-struct type receiver
func (d1 data) multiply(d2 data) data {
return d1 * d2
}
func main() {
value1 := data(23)
value2 := data(20)
res := value1.multiply(value2)
fmt.Println("Final result: ", res)
}
Pointer Receiver
// Author structure
type author struct {
name string
branch string
particles int
}
// Method with a receiver of author type
func (a *author) show(abranch string) {
(*a).branch = abranch
}
// Main function
func main() {
// Initializing the values
// of the author structure
res := author{
name: "Sona",
branch: "CSE",
}
fmt.Println("Author's name: ", res.name)
fmt.Println("Branch Name(Before): ", res.branch)
// Creating a pointer
p := &res
// Calling the show method
p.show("ECE")
fmt.Println("Author's name: ", res.name)
fmt.Println("Branch Name(After): ", res.branch)
}
Interface
type I interface {
M()
}
type T struct {
S string
}
// This method means type T implements the interface I,
// but we don't need to explicitly declare that it does so.
func (t T) M() {
fmt.Println(t.S)
}
func main() {
var i I = T{"hello"}
i.M()
}
Interface values with nil underlying values: If the concrete value inside the interface itself is nil, the method will be called with a nil receiver.
The empty interface: An empty interface may hold values of any type. (Every type implements at least zero methods.)
func main() {
var i interface{}
describe(i)
i = 42
describe(i)
i = "hello"
describe(i)
}
func describe(i interface{}) {
fmt.Printf("(%v, %T)\n", i, i)
}
Type assertions
t, ok := i.(T)
If i holds a T, then t will be the underlying value and ok will be true.
If not, ok will be false and t will be the zero value of type T, and no panic occurs.
Type Switches
switch v := i.(type) {
case T:
// here v has type T
case S:
// here v has type S
default:
// no match; here v has the same type as i
}
Down Casting
type Human interface {
walk() string
}
type Person struct {
name string
age int
}
func main() {
var h Human = Person{"Moein", 20}
fmt.Println(h.(Person).age) // Down casting
}
Map
var a = map[KeyType]ValueType{key1:value1, key2:value2,...}
var a = make(map[KeyType]ValueType)
delete(map_name, key)
val, ok := map_name[key] // ok is true if key is present in the map, else false
String
In Go language, strings are different from other languages like Java, C++, Python, etc. it is a sequence of variable-width characters where each and every character is represented by one or more bytes using UTF-8 Encoding. In Go language, strings are immutable.
Access Bytes
The string is of a byte so, we can access each byte of the given string.
func main() {
str := "Welcome to GeeksforGeeks"
for c := 0; c < len(str); c++ {
fmt.Printf("\nCharacter = %c Bytes = %v", str, str)
}
}
Output:
Character = W Bytes = 87
Character = e Bytes = 101
Character = l Bytes = 108
...
Create String From Slice
myslice1 := []byte{0x47, 0x65, 0x65, 0x6b, 0x73}
mystring1 := string(myslice1)
String Functions
p("Contains: ", s.Contains("test", "es"))
p("Count: ", s.Count("test", "t"))
p("HasPrefix: ", s.HasPrefix("test", "te"))
p("HasSuffix: ", s.HasSuffix("test", "st"))
p("Index: ", s.Index("test", "e"))
p("Join: ", s.Join([]string{"a", "b"}, "-"))
p("Repeat: ", s.Repeat("a", 5))
p("Replace: ", s.Replace("foo", "o", "0", -1))
p("Replace: ", s.Replace("foo", "o", "0", 1))
p("Split: ", s.Split("a-b-c-d-e", "-"))
p("ToLower: ", s.ToLower("TEST"))
p("ToUpper: ", s.ToUpper("test"))
Contains: true
Count: 2
HasPrefix: true
HasSuffix: true
Index: 1
Join: a-b
Repeat: aaaaa
Replace: f00
Replace: f0o
Split: [a b c d e]
ToLower: test
ToUpper: TEST
Concurrency
Channel
go f(x, y, z) // starts a new goroutine
ch := make(chan int, 100) // channel of integers, buffer size 100
v, ok := <-ch // receives from channel ch
close(ch) // closes channel ch
Only the sender should close a channel, never the receiver. Sending on a closed channel will cause a panic.
The loop for i := range c receives values from the channel repeatedly until it is closed.
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
default:
fmt.Println("default")
}
A select blocks until one of its cases can run, then it executes that case. It chooses one at random if multiple are ready.
Mutex
Note that mutexes must not be copied
type Container struct {
mu sync.Mutex
counters map[string]int
}
func (c *Container) inc(name string) {
c.mu.Lock()
defer c.mu.Unlock() //using a defer statement.
c.counters[name]++
}
WaitGroup
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
i := i
go func() {
defer wg.Done()
worker(i)
}()
}
wg.Wait()
Atomic
import "sync/atomic"
func main() {
var ops uint64
atomic.AddUint64(&ops, 1)
}
Reading atomics safely while they are being updated is also possible, using functions like atomic.LoadUint64.
time Package
tick := time.Tick(100 * time.Millisecond)
boom := time.After(500 * time.Millisecond)
timer := time.NewTimer(2 * time.Second)
<-timer.C
//One reason a timer may be useful is that you can cancel the timer before it fires.
stop := timer.Stop()
if stop {
fmt.Println("Timer stopped")
}
The tick channel will receive a value every 100ms. The boom channel will receive a single value after 500ms.
Sort Package
Built-in functions
sort package implements sorting for built-ins and user-defined types.
sort.Strings(strs)
sort.Ints(ints)
sort.IntsAreSorted(ints)
Custom Sort
sort.Slice(p, func(i, j int) bool {
return p[i].age < p[j].age
})
Error
Create a new error:
error := errors.New("Invalid Name")
error := fmt.Errorf("%d is negative\nAge can't be negative", age)
For custom errors, implement Error() function.
Wrap and Unwrap errors:
wrap = fmt.Errorf("...%w...",criticalError,...)
errors.Unwrap(wrap)
File
Read
content, err := os.ReadFile("test.txt") // returns []byte
// Read line by line
f, err := os.Open("test.txt")
scanner := bufio.NewScanner(f)
for scanner.Scan() {
s := scanner.Text()
fmt.Println(s)
}
Generics
func MapKeys[K comparable, V any](m map[K]V) []K {
r := make([]K, 0, len(m))
for k := range m {
r = append(r, k)
}
return r
}
K has the comparable constraint, meaning that we can compare values of this type with the == and != operators. V has the any constraint, meaning that it’s not restricted in any way (any is an alias for interface{}).
CLI
Arguments and Flags
args := os.Args // All arguments
value := flag.String("action", "read", "a string that represent the action")
flag.Parse() // This should be called after all flags are defined and before flags are accessed by the program.
flag.Args() // All arguments after flags (tail arguments)
fmt.Println(*value)
Subcommands
Create a custom subcommand:
fooCmd := flag.NewFlagSet("foo", flag.ExitOnError)
fooEnable := fooCmd.Bool("enable", false, "enable")
fooCmd.Parse(os.Args[2:])
fooCmd.Args()
HTTP
Parse URL
u, err := url.Parse(r.URL.String())
email, ok := u.Query()["email"]
Client
resp, _ := http.Get("https://google.com")
defer resp.Body.Close()
Server
func root(w http.ResponseWriter, _ *http.Request) {
m := map[string]any{
"name": "Moein",
"age": 20,
"isNoob": true,
}
enc := json.NewEncoder(w)
enc.Encode(m)
}
func main() {
http.HandleFunc("/", root)
http.ListenAndServe("localhost:80", nil)
}
Hash
s := "sha256 this string"
h := sha256.New()
h.Write([]byte(s))
bs := h.Sum(nil)
Handwrite Notes
Difference Between var and :=
var |
:= |
|---|---|
| Can be used inside and outside of functions | Can only be used inside functions |
| Variable declaration and value assignment can be done separately | Variable declaration and value assignment cannot be done separately (must be done in the same line) |
rune datatype
rune in Go is a data type that stores codes that represent Unicode characters. This method results in an encoded output of variable length from 1-4 Bytes. For this reason, rune is also known as an alias for int32, as each rune can store an integer value of at most 32-bits.
Furthermore, Go does not have a char data type, so all variables initialized with a character would automatically be typecasted into int32, which, in this case, represents a rune.
Here, it might seem like rune is the char alternative for Go, but that is not actually true. In Go, strings are actually made up of sequences of bytes, not a sequence of rune.
package main
import "fmt"
func main() {
var str string = "ABCD"
r_array := []rune(str)
fmt.Printf("Array of rune values for A, B, C and D: %U\n", r_array)
}
Stringer Interface
A Stringer is a type that can describe itself as a string. The fmt package (and many others) look for this interface to print values.
type Stringer interface {
String() string
}