Go Tips

取map的size #

用 len() 函数

遍历map #

1
2
3
for k, v := range m { 
    fmt.Printf("key[%s] value[%s]\n", k, v)
}

参考

JSON转换 #

使用encoding/json包的 Unmarshal 和 Marshal 方法,结构体要注明 json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main

import (
    "fmt"
    "encoding/json"
)

type Data struct {
    Votes *Votes `json:"votes"`
    Count string `json:"count,omitempty"`
}

type Votes struct {
    OptionA string `json:"option_A"`
}

func main() {
    s := `{ "votes": { "option_A": "3" } }`
    data := &Data{
        Votes: &Votes{},
    }
    err := json.Unmarshal([]byte(s), data)
    fmt.Println(err)
    fmt.Println(data.Votes)

    s2, _ := json.Marshal(data)
    fmt.Println(string(s2))

    data.Count = "2"
    s3, _ := json.Marshal(data)
    fmt.Println(string(s3))
}

参考

指定interface{}的类型 #

1
2
3
4
var a interface{}
var b string

b = a.(string)

go run 失败 #

1
2
3
4
$ go run main.go
# command-line-arguments
.\main.go:4:2: undefined: a
.\main.go:5:2: undefined: average2

main.go 文件引用了 package main 中的另外两个文件中的函数。所以 run 命令应该是这样的

1
$ go run main.go demo.go average2.go 

要把关联的文件都加载才行。

* 运算符 #

  • 声明变量为指针类型
    1
    2
    3
    
    var myIntPointer *int
    myInt := 4
    myIntPointer = &myInt
    
  • 获取指针的值
    1
    
    fmt.Println(*myIntPointer) // 4
    
  • 修改指针指向的变量的值
    1
    2
    3
    4
    5
    6
    
    var myIntPointer *int
    myInt := 4
    myIntPointer = &myInt
    fmt.Println(*myIntPointer) //4
    *myIntPointer = 8
    fmt.Println(myInt) //8
    

单元测试 #

命令是 go test 文件名,它会寻找以 _test.go 结尾的文件

  • -v 会打印出执行的用例的名字
  • -run 加关键字,只会执行相关的文件

一个 _test.go 文件内可以有多个测试函数,函数的名字要以 Test 开头

install #

go install 命令会对当前目录的go程序进行编译并安装编译后的结果文件到指定目录。可以到 cd $GOPATH/bin 目录中查看。

安装后的程序是以目录名命名的。

go install -v -work // 
go install -a -v -work // 强行重新安装指定代码包及其依赖包

参考

go get #

go get 命令会下载并install一个go程序

刚开始本地创建了项目时,要进行 go mode init 会创建一个 go.mod 文件

module gg

go 1.14

require (
	github.com/atotto/clipboard v0.1.2
	github.com/urfave/cli/v2 v2.3.0
)

其中的 module 是你当前文件夹的名字

当把它提交到 github 后,用 go get 命令安装时,命令应该是这样的

go get github.com/wangshushuo/gg

然后会报一个错误

$ go get github.com/wangshushuo/[email protected]
go get: github.com/wangshushuo/[email protected]: parsing go.mod:
module declares its path as: gg
but was required as: github.com/wangshushuo/gg

module 这个字段现在是 gg ,要求的是 github.com/wangshushuo/gg 。

所以需要在 go.mod 文件中将 gg 改为 github.com/wangshushuo/gg 。

http 请求 #

form

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
client := &http.Client{}
form := url.Values{}
form.Add("username", "xxx")
form.Add("password", "xxx")

req, err := http.NewRequest("POST", "http://xxx/api/loginapi", strings.NewReader(form.Encode()))

if req != nil {
    req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
}
if err != nil {
    fmt.Println("err")
    // handle error
}
res, _ := client.Do(req)
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
fmt.Println(string(body))

json

1
2
3
4
5
6
7
loginInfo := LoginInfo{
    Username: "王书硕",
    Password: "ISxUo7Ol",
}
loginInfoJson, err := json.Marshal(loginInfo)

req, err := http.NewRequest("POST", "http://xxx/api/loginapi", bytes.NewBuffer(loginInfoJson))

html/template #

简单的方式

1
temp, err := template.ParseFiles("tech_keyword/category/view.html")

这样的模板不能植入方法,需要用template.New方法

1
2
3
4
5
6
7
func demo() {
    funcMap := template.FuncMap{"add": add}
    temp, err := template.New("view.html").Funcs(funcMap).ParseFiles("tech_keyword/category/view.html")
}
func add(a, b int) int {
	return a + b
}

New的参数需要是ParseFiles中文件名一样,不然会报错

error: template: “…” is an incomplete or empty template

template bing data #

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
func (o *OAuth2) view(w http.ResponseWriter, r *http.Request) {
	temp, _ := template.New("view.html").ParseFiles("oauth2/view.gohtml")
	res, _ := o.client.Get("https://api.github.com/user")
	robots, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		log.Println("err: ", err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	fmt.Printf("%s", string(robots))
	userInfo := UserInfoData{}
	err = json.Unmarshal(robots, &userInfo)
	if err != nil {
		log.Println("err: ", err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	_ = temp.Execute(w, userInfo)
}

io #

读取http请求的body #

http.Request中的Body是一个io.ReadCloser,可以使用ioutil.ReadAll将其中的内容全部读出来。

byte string #

1
2
3
4
5
// 将字符串转化为byte
[]byte("hello")

// 将byte转化为string
string([]byte("hello"))

os #

打开文件 #

1
f, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)

清空文件内容 #

1
2
3
if err := os.Truncate(filePath, 0); err != nil {
    log.Printf("Failed to truncate: %v", err)
}

Truncate方法是用来剪切文件大小的。0就相当于把内容清空。

writer #

1
2
w := csv.NewWriter(f)
w.Write(record)

用Write往文件中写入内容,是增量的写入。

context #

1
2
3
c.Ctx = context.WithValue(c.Ctx, "token", "123")
// 或
context.WithValue(context.Background(), "token", resToken.Data.Token)

讲值存到context中。

1
c.Ctx.Value("token").(string)

获取值

值传递 #

map和slice创建后得到的就是它们的指针,所以赋值给变量后,变量就是一个指针,当把他们传给方法、函数时,传递的是变量的值。但是值里面其实是指针。