go基础整理

main函数和init函数

  Go里面有两个保留的函数:init函数(能够应用于所有的package)和main函数(只能应用于package main)。这两个函数在定义时不能有任何的参数和返回值。虽然一个package里面可以写任意多个init函数,但这无论是对于可读性还是以后的可维护性来说,我们都强烈建议用户在一个package中每个文件只写一个init函数。
  Go程序会自动调用init()和main(),所以你不需要在任何地方调用这两个函数。每个package中的init函数都是可选的,但package main就必须包含一个main函数。
  程序的初始化和执行都起始于main包。如果main包还导入了其它的包,那么就会在编译时将它们依次导入。有时一个包会被多个包同时导入,那么它只会被导入一次(例如很多包可能都会用到fmt包,但它只会被导入一次,因为没有必要导入多次)。当一个包被导入时,如果该包还导入了其它的包,那么会先将其它包导入进来,然后再对这些包中的包级常量和变量进行初始化,接着执行init函数(如果有的话),依次类推。等所有被导入的包都加载完毕了,就会开始对main包中的包级常量和变量进行初始化,然后执行main包中的init函数(如果存在的话),最后执行main函数。

json处理

json 中提供的处理 json 的标准包是 encoding/json,主要使用的是以下两个方法:

1
2
3
4
5
6
7
8
9
10
11
// 序列化
func Marshal(v interface{}) ([]byte, error)
// 反序列化
func Unmarshal(data []byte, v interface{}) error
序列化前后的数据结构有以下的对应关系:
bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null

Unmarshal
这是一个反序列化的过程,将 JSON 串重新组装成结构体。
已知类型解析
JSON 解析的时候只会解析能找得到的字段,找不到的字段会被忽略,这样的一个好处是:当你接收到一个很大的 JSON 数据结构而你却只想获取其中的部分数据的时候,你只需将你想要的数据对应的字段名大写,即可轻松解决这个问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main
import (
"encoding/json"
"fmt"
)
type Animal struct {
Name string
Order string
}
func main() {
var jsonBlob = []byte(`[
{"Name": "Platypus", "Order": "Monotremata"},
{"Name": "Quoll", "Order": "Dasyuromorphia"}
]`)

var animals []Animal
err := json.Unmarshal(jsonBlob, &animals)
if err != nil {
fmt.Println("error:", err)
}
fmt.Printf("%+v", animals)

未知解析类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var f interface{}
b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)
json.Unmarshal(b, &f)
for k, v := range f.(map[string]interface{}) {
switch vv := v.(type) {
case string:
fmt.Println(k, "is string", vv)
case int:
fmt.Println(k, "is int ", vv)
case float64:
fmt.Println(k, "is float64 ", vv)
case []interface{}:
fmt.Println(k, "is array:")
for i, j := range vv {
fmt.Println(i, j)
}
}
}

Marshal
这是序列化的过程,将结构体序列化成一个 JSON 串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
"encoding/json"
"fmt"
)
type Animal struct {
Name string `json:"name"`
Order string `json:"order"`
}
func main() {
var animals []Animal
animals = append(animals, Animal{Name: "Platypus", Order: "Monotremata"})
animals = append(animals, Animal{Name: "Quoll", Order: "Dasyuromorphia"})

jsonStr, err := json.Marshal(animals)
if err != nil {
fmt.Println("error:", err)
}

fmt.Println(string(jsonStr))
}

json tag 有很多值可以取,同时有着不同的含义,比如:
tag 是 “-“,表示该字段不会输出到 JSON.
tag 中带有自定义名称,那么这个自定义名称会出现在 JSON 的字段名中,比如上面小写字母开头的 name.
tag 中带有 “omitempty” 选项,那么如果该字段值为空,就不会输出到JSON 串中.
如果字段类型是 bool, string, int, int64 等,而 tag 中带有”,string” 选项,那么该字段在输出到 JSON 时,会把该字段对应的值转换成 JSON 字符串.

net/http包处理请求

golang类型断言

类型断言是一个使用在接口值上的操作
有时候,我们可能需要知道某个接口类型的实际类型,比如某个方法需要接收多种类型的数据并需做分别处理时,我们可以把形参设为空接口类型以接收任意类型的值,但是我们怎么反向知道里面实际保存了的是哪个类型的对象呢?
• Comma-ok 断言语法
value,ok := x.(T)
x表示一个接口的类型,T表示一个类型(也可为接口类型)
该断言表达式会返回x的值和一个布尔值 可根据该布尔值判断x是否为T类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func main() {
var x interface{}
x = 10
value, ok := x.(int)
fmt.Print(value, ",", ok)
}
func judgeType(a interface{}) {
switch a.(type) {
case int:
fmt.Println("the type of a is int")
case string:
fmt.Println("the type of a is string")
case float64:
fmt.Println("the type of a is float")
default:
fmt.Println("unknown type")
}
}