Skip to content

Instantly share code, notes, and snippets.

@keegoo
Last active April 3, 2025 04:03
Show Gist options
  • Save keegoo/00688540048db106b138da10e2cff316 to your computer and use it in GitHub Desktop.
Save keegoo/00688540048db106b138da10e2cff316 to your computer and use it in GitHub Desktop.
a cheatsheet for go lang

Type

package main
import "fmt"

func main() {

    myString := "dog"
    myByte := []byte("cat")
    var myInt   int = 123456876   // The int, unit and uintptr types are usually 32 bits wide on 32-bit systems and 64 bits wide on 64-bit systems.
    var myInt8  int8 = 10
    var myInt32 int32 = 123456789
    var myInt64 int64 = 34567898765434567
    myPString := &myString
    myPInt := &myInt 
    myPByte := &myByte
    myPInt8 := &myInt8
    myPInt32 := &myInt32
    myPInt64 := &myInt64
  
    fmt.Println(getType(myInt))     // int
    fmt.Println(getType(myString))  // string
    fmt.Println(getType(myByte))    // []uint8
    fmt.Println(getType(myInt8))    // int8
    fmt.Println(getType(myInt32))   // int32
    fmt.Println(getType(myInt64))   // int64

    fmt.Println(getType(myPInt))    // *int
    fmt.Println(getType(myPString)) // *string
    fmt.Println(getType(myPByte))   // *[]uint8
    fmt.Println(getType(myPInt8))   // *int8
    fmt.Println(getType(myPInt32))  // *int32
    fmt.Println(getType(myPInt64))  // *int64
}


func getType(anything interface{}) (string) {
    var s string
    switch anything.(type) {
        case []byte:  s = "[]byte"
        case string:  s = "string"
        case int:     s = "int"
        case int8:    s = "int8"
        case int32:   s = "int32"
        case int64:   s = "int64"
        // pointer
        case *[]byte: s = "*[]byte"
        case *string: s = "*string"
        case *int:    s = "*int"
        case *int8:   s = "*int8"
        case *int32:  s = "*int32"
        case *int64:  s = "*int64"
        default:      s = "unknow"
    }
    return s
}

Map

There's some key differences between Map and Struct:

  • Map is dynamic, you can add/remove keys at runtime. While Struct is fixed.
  • Map is using hashing under the hood, so it needs more memory than Struct, and also a bit more slower.
  • someMap["keyname"] instead of someStruct.keyname.
  • Map is iterable, while Struct is NOT by default.
package main

import "fmt"

type Person struct {
    Age  int
    City string
}

func main() {
    // 1. Simple map: Set and Get value
    fruitPrices := map[string]float64{
        "apple":  1.99,
        "banana": 0.99,
    }

    fmt.Println("Price of apple:", fruitPrices["apple"])

    // 2. Map with complex data type (struct)
    people := map[string]Person{
        "Alice": {Age: 30, City: "New York"},
        "Bob":   {Age: 25, City: "San Francisco"},
    }

    // Get a value and check if key exists
    if person, exists := people["Alice"]; exists {
        fmt.Println("Alice's age:", person.Age, ", City:", person.City)
    } else {
        fmt.Println("Alice not found")
    }

    // 3. Iterate over a map
    for name, person := range people {
        fmt.Println("Name:", name, "Age:", person.Age, "City:", person.City)
    }
}

Struct and Method

package main
import "fmt"

type MyStruct struct {
    Name string
}

func (m MyStruct) ValueMethod() {
    m.Name = "Changed in ValueMethod"
    fmt.Println("Inside ValueMethod: ", m.Name)
}

func (m *MyStruct) PointerMethod() {
    m.Name = "Changed in PointerMethod"
    fmt.Println("Inside PointerMethod: ", m.Name)
}

func main() {
    example := MyStruct{Name: "Original"}
    example.ValueMethod()                               // Inside ValueMethod: Changed in ValueMethod
    fmt.Println("After ValueMethod: ", example.Name)    // After ValueMethod: Original
  
    example.PointerMethod()                             // Inside ValueMethod: Changed in ValueMethod
    fmt.Println("After PointerMethod: ", example.Name)  // Inside ValueMethod: Changed in ValueMethod
}

Interface

In Go, interfaces are the way to implement duck typing.

package main

import "fmt"

// Define an interface for behavior
type Quacker interface {
    Quack() string
}

// Define a struct that implements the interface
type Duck struct {
    Name string
}
func (d Duck) Quack() string {
    return d.Name + " quacks like a duck!"
}

// Define another struct that "quacks"
type Dog struct {
    Name string
}
func (d Dog) Quack() string {
    return d.Name + " quacks like a dog!"
}

// Function that accepts any type that satisfies the Quacker interface
func describeQuacking(quacker Quacker) {
    fmt.Println(quacker.Quack())
}

func main() {
    myDuck := Duck{Name: "Daffy"}
    myDog := Dog{Name: "Buddy"}
  
    describeQuacking(myDuck) // Daffy quacks like a duck!
    describeQuacking(myDog)  // Buddy quacks like a dog!
}

If you come across some code and are wondering whether a certain type is a struct or an interface, you can usually make a distinction by looking at its name.

  • interface in Go are typically named with a verb or an action, representing behaviors or actions that a type should implement. For example, Writer, Reader, and EventRecorder
  • struct, on the other hand, are usually nouns that represent a concrete type or an object. Examples include Event, Client, or AzureReconciler
type AzureReconciler struct {
	client.Client                       // interface
	Log    logr.Logger                  // interface
	Scheme *runtime.Scheme              // struct
	eventRecorder record.EventRecorder  // interface
}
@keegoo
Copy link
Author

keegoo commented Apr 1, 2025

Compose

Compose is achieved through interface in go lang. Following is an example.

package main

import "fmt"

// ===== imagine those are third party libraries =====

// ----- -----
// httpClient interface
type httpClient interface {
	GetData() string
}
// Concrete type implementing httpClient interface
type MyHttpClient struct{}
func (m *MyHttpClient) GetData() string {
	return "Fetched data from HTTP client"
}

// ----- -----
// dbClient interface
type dbClient interface {
	SaveData(data string) bool
}
// Concrete type implementing dbClient interface
type MyDbClient struct{}

func (m *MyDbClient) SaveData(data string) bool {
	fmt.Println("Data saved to DB:", data)
	return true
}

// ===== those are your codes, where you would like to reuse the third party libraries =====

// ----- -----
// Now, define a struct that will use all these interfaces
type MyType struct {
	HttpClient httpClient
	DbClient   dbClient
}
// Define a method for MyType that uses the interfaces to perform actions
func (m *MyType) DoSomething() {
	data := m.HttpClient.GetData()
	m.DbClient.SaveData(data)
}

func main() {
	// Create concrete types
	httpClient := &MyHttpClient{}
	dbClient := &MyDbClient{}

	// Create MyType instance and inject the concrete implementations
	myInstance := &MyType{
		HttpClient: httpClient,
		DbClient:   dbClient,
	}

	// Call the method that uses the interfaces
	myInstance.DoSomething()
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment