Go 常用语法

env

go -h
go env
go version # go1.20.1 darwin/amd64

# GOROOT: Go 语言的安装路径
# GOPATH: 工作区目录的路径(第三方包保存的目录),bin, pkg(安装后的 *.a 文件, archive file), src
# GOBIN: Go 可执行文件的路径

go build # 构建
go install # 安装

go build -a # 不但目标代码包总是会被编译,它依赖的代码包也总会被编译,即使依赖的是标准库中的代码包也是如此。
go build -n # 只查看,不执行
go build -x # 查看执行详情
go build -v # 查看编译的代码包的名称

Hello, Go!

// hello.go  The program entry main function must be in a code package named main.
package main

import (
  "fmt"
)

func main() {
  str := "world"
  text := fmt.Sprintf("hello %s! AwesomeProgram.", str)
  fmt.Println(text)
}

run

// run
go run hello.go
go build hello.go; ./hello

Command Argv

package main
 
import (
	"flag"
	"fmt"
)
var name string

func init() {
	flag.StringVar(&name, "name", "everyone", "The greeting object.")
}

func main() {
	flag.Parse()
	fmt.Printf("Hello, %s!", name)
}

//
go run test.go -h
go run test.go -name=123 // Hello, 123!

init

package main

import "fmt"

func init() {
  fmt.Println("init 1")
}

func main() {
  fmt.Println("main")
}

func init() {
  fmt.Println("init 2")
}

// init 1
// init 2
// main

import

import format "fmt" // format.Println()
import "fmt" // fmt.Println()
import . "fmt" // use Println directly, not recommended
import _ "net/http/pprof" // used to load pprof package, it's init function will be called.

struct

type Book struct {
  title, author string
  pages         int
}

book = Book{author: "Book author", pages: 256, title: "Book Name"}
// or
book = Book{}
fmt.Println(book.title)

Array, Slice, Map

[100]Book // Array, with element type Book

[]Book // Slide, with element type Book

map[string]Book // Map, with key value: string - Book 

books := [...]Book {
  {title: "title1"},
  {title: "title2"},
  {title: "title3"},
}
len(books) // 3
cap(books) // 3

数组

var number_array [3]int // [0, 0, 0]
append(number_array, 1) // Error
number_array[0] = 1 // [1, 0, 0]

切片

var number_slice []int // []
// Recreate to append
number_slice = append(number_slice, 1) // [1]
// Create a new slice from an array
some_numbers := number_array[0:1] // [0]

s0 := []int{1, 2, 3}
s1 := append(s0, 4, 5)

fmt.Println(s0, cap(s0)) // [1, 2, 3] 3
fmt.Println(s1, cap(s1)) // [1, 2, 3, 4, 5] 6
// Note the cap is 6, not 5

s3 := append(s0, s0...) // [1, 2, 3, 1, 2, 3]

字典

m := map[string]int{"abc": 123, "xyz": 789}
n, is_exist := m["hello"] // 0 false
m = nil
fmt.Println(m["abc"]) // 0
m["dfg"] = 456
delete(m, "dfg")

your_map := make(map[string]int)
your_map["key"] = 1
fmt.Println(your_map["key"]) // 1
// Remove key
delete(your_map, "key")

make

m := make(map[string]int)) // map[]

s := make([]int, 3, 5)
fmt.Println(s, len(s), cap(s)) // [0 0 0] 3 5

iterate

for key, element = range aContainer {
  // do something
}

clone

sClone := append(s[:0:0], s...) // s is a slice

// or
var sClone []T
if s != nil {
  sClone = make([]T, len(s))
  copy(sClone, s)
}

strings

import (
  "strings"
)

len("hello")
strings.HasPrefix("helloWorld", "hello") // true
strings.Contains("something", "some") // true

function parameters

func Sum(values ...int64) (sum int64) {
  // values's type is []int64。
  sum = 0
  for _, v := range values {
    sum += v
  }
  return sum
}
Sum(2, 3, 5)

JSON

type Config struct {
    Name bool `json:"name"` // OK

    Name bool `json: "name"` // Error
    Name bool `json:name` // Error
}

循环

names := []string{"a", "b", "c"} // [a b c]
for i, name := range names {
  fmt.Printf("%d. %s", i+1, name)
}
// 1. a
// 2. b
// 3. c

goroutine

go say("hello") // run say in goroutine

Channel

ch := make(chan int, 10) // create channel

close(ch) // close channel

ch <- v // send v to ch

v = <-ch // accept v from ch
v, sentBeforeClosed = <-ch

cap(ch) // capacity
len(ch) // length

go func(ch <-chan int) {
  ch <- 123 // send 123 to ch
}
go func(ch chan<- int) {
  n := <-ch // get value from ch
}

Loop Channel

for x, ok := <-c; ok; x, ok = <-c {
  fmt.Println(x)
}

for v := range aChannel {
  // do something
}
// equivalent
for {
  v, ok = <-aChannel
  if !ok {
    break
  }
  // do something
}

select-case

package main

import "fmt"

func main() {
  c := make(chan string, 2)
  trySend := func(v string) {
    select {
    case c <- v:
    default: // 如果c的缓冲已满,则执行默认分支。
    }
  }
  tryReceive := func() string {
    select {
    case v := <-c: return v
    default: return "-" // 如果c的缓冲为空,则执行默认分支。
    }
  }
  trySend("Hello!") // 发送成功
  trySend("Hi!")    // 发送成功
  trySend("Bye!")   // 发送失败,但不会阻塞。
  // 下面这两行将接收成功。
  fmt.Println(tryReceive()) // Hello!
  fmt.Println(tryReceive()) // Hi!
  // 下面这行将接收失败。
  fmt.Println(tryReceive()) //
}

methods

type Book struct {
  pages int
}
func (b Book) Pages() int {
  return b.pages
}
func (b *Book) SetPages(pages int) {
  b.pages = pages
}

var book Book
book.SetPages(123) // = (*Book).SetPages(&book, 123)
book.Pages() // = Book.Pages(book)

接口

// res.Data is <interface {}>, res.Data > data is <[]interface {}>
// 断言res.Data是一个interface{}类型的切片
items, ok := res.Data.([]interface{}) 
if !ok {
    return
}

for i, item := range items {
	// 断言item是一个interface{}类型的map
    data, ok := item.(map[string]interface{}) 
    if !ok {
        continue 
    }

    id := data["id"]
	// 断言data["id"]是一个float64值
    if idFloat, ok := id.(float64); ok {
        // use idFloat 
    } else {
        // use default id
    }
}

使用 Delve 调试

# https://github.com/go-delve/delve
dlv debug app.go

Debugger 内部

# Set breakpoint
break [path/filename].go:[line_num]

# Run and should pauses at the breakpoint
continue

# Print variable
print [variable_name]

# Move to next line in the source
next

Gin

// Read Request Body in JSON
type GitHubInput struct {
  Zen string `json:"zen"`
}
var input GitHubInput
if err := c.ShouldBindJSON(&input); err != nil {
  c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  return
}
input.Zen

// Read Header
c.Request.Header.Get("X-GitHub-Event")

// HTTP Response
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
c.String(200, input.Zen)