Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Go Language Fundamentals: Core Concepts and Syntax

Tech May 11 6

Language Structure

package main

import (
    "fmt"
)

func main() {
    fmt.Print("Hello World!")
}

Execuiton:

go run main.go
go build main.go
./main

Go Modules

go env
go env -w GO111MODULE=on
go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/,https://goproxy.cn,direct

Environment Variables:

  • GOSUMDB - validates dependency integrity
  • GONOSUMDB - excludes specific domains from checksum verification
  • GONOPROXY - bypasses proxy for specific modules
  • GOPRIVATE - marks modules as private, bypassing proxy

Workflow:

  1. Enable GO111MODULE and configure proxy
  2. Create project directory: mkdir project/
  3. Create module directory: mkdir module/
  4. Initialize: go mod init module_name

Common Commands:

go mod init          # Initialize new module
go mod tidy          # Update dependencies
go mod download      # Download dependencies
go mod vendor        # Copy dependencies to vendor/
go mod verify        # Verify dependencies
go mod edit          # Manually edit go.mod

Package Imports

import "example/package"

Initialization Order:

  1. Package example loads → imports example2
  2. example2 loads → no further imports
  3. example2 executes global variables, constants, and init()
  4. example executes its global declarations
  5. Execution propagates upward

init() runs before main(), making it suitable for database connections and environment setup.

Blank Identifier:

import (
    _ "lib1"
)

This calls lib1's init() without causing unused import errors.

Variables

var a int = 10
var b = 10
c := 10
var d, e, f = 1, 2, 3

Notes:

  • := cannot reuse existing variables
  • Variable declarations are mandatory

Constants

const a int = 10

iota Usage:

const (
    a = iota  // 0
    b        // 1
    c        // 2
    d = "ha" // 3
    e        // "ha"
    f = 100  // 100
    g        // 100
    h = iota // 7
    i        // 8
)

iota is a special constant that resets to 0 in each const block and increments automatically.

Conditional Statements

If Statement

var a int
fmt.Scanf("%d", &a)
if a > 10 {
    fmt.Println("a > 10")
} else if a <= 10 {
    fmt.Println("a <= 10")
}

Switch Statement

switch i := b.(type) {
case nil:
    fmt.Println("b is nil")
case int:
    fmt.Println("b is int")
default:
    fmt.Println("b is string")
}

Fallthrough

switch i := 10 {
case 5:
    fmt.Println("i is 5")
case 10:
    fmt.Println("i is 10")
    fallthrough
default:
    fmt.Println("i is 15")
}
// Output: i is 10, i is 15

fallthrough forces execution of the next case, ignoring case matching.

Select Statement

Used exclusively with channels. Each case must be a channel operation (send or receive).

package main

import "fmt"

func main() {
    ch1 := make(chan string)
    ch2 := make(chan string)
    
    go func() {
        for {
            ch1 <- "ch1"
        }
    }()
    
    go func() {
        for {
            ch2 <- "ch2"
        }
    }()
    
    for {
        select {
        case msg1 := <-ch1:
            fmt.Println(msg1)
        case msg2 := <-ch2:
            fmt.Println(msg2)
        default:
            fmt.Println("no message received")
        }
    }
}

If no channel is ready and no default case exists, the select blocks.

Loops

// Range iteration
for key, value := range smap {
    // key and value
}

// Traditional for loop
for i := 10; i > 0; i-- {
    // loop body
}

// While-style loop
i := 20
for i > 10 {
    i--
}

// Infinite loop
for {
    // loop body
}

Break with Label:

re:
    for i := 10; i > 8; i-- {
        break re
    }

Functions

func functionName() (returnType1, returnType2) {
    // function body
    return
}

func max(num1, num2 int) int {
    if num1 > num2 {
        return num1
    }
    return num2
}

Note: All function parameters in Go are passed by value.

Arrays

Fixed-length, strongly-typed sequences:

var arr [3]int = [3]int{1, 2, 3}
arr := [3]int{1, 2, 3}
r := [...]int{99: -1}  // 100 elements, index 99 = -1
a := [...]int{1, 2, 3, 4, 5}  // length inferred as 5

Important: [3]int and [4]int are different types.

Slices

Dynamic-length arrays backed by an underlying array. A slice consists of: pointer to first element, length, and capacity.

var slice1 []int = make([]int, length, capacity)
slice1 := make([]int, length, capacity)
s := []int{1, 2, 3}

append() Behavior: When capacity is exceeded, Go allocates a new array (2x capacity) and copies existing elements. Modifications to the new slice won't affect the original array.

Maps

Unordered key-value pairs:

// Declaration
var myMap1 map[string]int  // nil map
myMap1 = make(map[string]int, 10)
myMap1 := make(map[string]int)
myMap1 := map[string]int{
    "one": 1,
    "two": 2,
}

// Operations
myMap2["china"] = "Beijing"  // add/update
delete(myMap2, "china")       // delete

// Iteration
for key, value := range myMap2 {
    fmt.Println(key, value)
}

Maps are reference types when passed as parameters.

Structs

type MyInt int

type Book struct {
    name  string
    price float64
}

func (b Book) GetName() string {
    return b.name
}

Method Receivers: Value vs Pointer

// Value receiver - receives a copy
func (b Book) SetName(newName string) {
    b.name = newName  // doesn't affect original
}

// Pointer receiver - receives a reference
func (b *Book) SetName(newName string) {
    b.name = newName  // modifies original
}

Composition (Not Inheritance)

type Person struct {
    name string
    age  int
}

type SuperHero struct {
    Person
    canFly bool
}

// Initialization
hero := SuperHero{Person{"John", 30}, true}
// or
var hero SuperHero
hero.name = "John"
hero.age = 30
hero.canFly = true

Go uses composition instead of inheritance.

Struct Tags

type Movie struct {
    Title string `json:"title"`
    Price string `json:"price"`
}

// Struct to JSON
jsonStr, err := json.Marshal(movie)

// JSON to Struct
var movie Movie
err = json.Unmarshal(jsonStr, &movie)
type Movie struct {
    Title string `info:"title" doc:"movie title"`
}

func getTagContent(arg interface{}) {
    t := reflect.TypeOf(arg).Elem()
    for i := 0; i < t.NumField(); i++ {
        fmt.Println(t.Field(i).Tag.Get("info"))
    }
}

Interfaces and Polymorphism

type Action interface {
    Sleep()
    GetColor() string
    SetColor(color string)
}

type Animal struct {
    name  string
    color string
}

func (a *Animal) Sleep() {}
func (a *Animal) GetColor() string { return a.color }
func (a *Animal) SetColor(color string) { a.color = color }

var cat Action = &Animal{name: "cat"}
cat.SetColor("black")

A type implements an interface by providing all method definitions.

Empty Interface

func process(arg interface{}) {
    // Type assertion
    value, ok := arg.(string)
    if ok {
        fmt.Println("string value:", value)
    }
    
    // Type switch
    switch v := arg.(type) {
    case string:
        fmt.Println("string:", v)
    case int:
        fmt.Println("int:", v)
    }
}

Every type implements the empty interface interface{}. Internally, a variable consists of a type and value (pair).

defer

Executes after the surrounding function returns, but before the return statement completes. Multiple defers execute in LIFO order.

func main() {
    defer fmt.Println("world")
    fmt.Println("hello")
}
// Output: hello, world

Recover

func recoverFromPanic() {
    if err := recover(); err != nil {
        fmt.Println("Recovered:", err)
    }
}

func main() {
    defer recoverFromPanic()
    panic("something went wrong")
}

return executes before defer within the same function.

Reflection

reflect.TypeOf(value)   // returns reflect.Type
reflect.ValueOf(value)  // returns reflect.Value

// Using %T in fmt prints the type
fmt.Printf("%T\n", variable)

Goroutines

Lightweight threads managed by the Go runtime. The main goroutine must not finish before others complete.

func worker() {
    for i := 1; ; i++ {
        fmt.Println("worker:", i)
        time.Sleep(1 * time.Second)
    }
}

func main() {
    go worker()
    for i := 1; ; i++ {
        fmt.Println("main:", i)
        time.Sleep(1 * time.Second)
    }
}

Without a wait mechanism, main may exit before goroutines complete.

WaitGroup

var wg sync.WaitGroup

func task(id int) {
    defer wg.Done()
    fmt.Printf("Task %d completed\n", id)
}

func main() {
    for i := 1; i <= 3; i++ {
        wg.Add(1)
        go task(i)
    }
    wg.Wait()
}

Channels

Communication mechanism between goroutines:

ch := make(chan int)
ch <- 10     // send
value := <-ch  // receive

Unbuffered Channels

Both send and receive block until the other party is ready.

Buffered Channels

ch := make(chan int, 3)
fmt.Println(len(ch), cap(ch))

Closing Channels

func produce(ch chan int) {
    for i := 0; i <= 5; i++ {
        ch <- i
        if i == 5 {
            close(ch)
            return
        }
    }
}

func main() {
    ch := make(chan int)
    go produce(ch)
    for {
        if value, ok := <-ch; ok {
            fmt.Println("Received:", value)
        } else {
            break
        }
    }
    fmt.Println("Channel closed")
}

Only close channels when no further sends are expected.

Channel with Range and Select

// Using range to receive from channel
for data := range ch {
    fmt.Println(data)
}

// Using select for multiple channels
for {
    select {
    case <-ch1:
        fmt.Println("ch1 readable")
    case ch2 <- data:
        fmt.Println("ch2 writable")
    }
}

range automatically stops when the channel is closed.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.