0%

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import (
"encoding/json"
"fmt"
)

// 反序列化
type User struct {
UserName string `json:"username"`
Age int `json:"age"`
Sex string `json:"sex"`
Phone string `json:"phone"`
}

// 结构体转json
func structForJson() (jsonStr string) {
u := &User{
UserName: "root",
Age: 18,
Sex: "男",
Phone: "13160000001",
}
j, err := json.Marshal(u)
if err != nil {
fmt.Printf("struct for json err:%v\n", err)
return
}
jsonStr = string(j)
return
}

// json转结构体
func jsonForStruct() {
var u User
jsonStr := structForJson()
err := json.Unmarshal([]byte(jsonStr), &u)
if err != nil {
fmt.Printf("json for struct err:%v\n", err)
return
}
fmt.Printf("struct is %v\n", u)
}

// map转json
func mapForJson() (jsonStr string) {
var m map[string]interface{}
m = make(map[string]interface{})
m["username"] = "admin"
m["age"] = 19
m["sex"] = "男"
m["phone"] = "13770000000"
mj, err := json.Marshal(m)
if err != nil {
fmt.Printf("map for json err:%v\n", err)
return
}
jsonStr = string(mj)
return
}

// json转map
func jsonForMap() {
var m map[string]interface{}
m = make(map[string]interface{})
jsonStr := mapForJson()
err := json.Unmarshal([]byte(jsonStr), &m)
if err != nil {
fmt.Printf("json for map err:%v\n", err)
return
}
fmt.Printf("map is %v\n", m)
}

// slice转json
func sliceForJson() (jsonStr string) {
var l []*User
u1 := &User{
UserName: "u1",
Age: 18,
Sex: "男",
Phone: "110",
}
u2 := &User{
UserName: "u2",
Age: 28,
Sex: "男",
Phone: "120",
}
l = append(l, u1)
l = append(l, u2)
lj, err := json.Marshal(l)
if err != nil {
fmt.Printf("slice for json err:%v\n", err)
return
}
jsonStr = string(lj)
return
}

// json转slice
func jsonForSlice() {
var l []User
var u1 User
var u2 User
l = append(l, u1)
l = append(l, u2)
jsonStr := sliceForJson()
err := json.Unmarshal([]byte(jsonStr), &l)
if err != nil {
fmt.Printf("json for map err:%v\n", err)
return
}
fmt.Printf("map is %v\n", l)
}

func main() {
jsonForStruct()
jsonForMap()
jsonForSlice()
}
----------------------
struct is {root 18 男 13160000001}
map is map[age:19 phone:13770000000 sex:男 username:admin]
map is [{u1 18 男 110} {u2 28 男 120}]

仅仅是对Go语言接口的练习,并无实际业务代码!

  • balance.go 接口:

    1
    2
    3
    4
    5
    6
    package balance

    type Balance interface {
    DoBalance([]*Instance) (*Instance, error)
    }

  • instance.go 模拟服务器实例

    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
    package balance

    import "strconv"

    type Instance struct {
    host string
    port int
    }

    func NewInstance(host string, port int) *Instance {
    return &Instance{
    host: host,
    port: port,
    }
    }

    func (this *Instance) GetHost() string {
    return this.host
    }

    func (this *Instance) GetPort() int {
    return this.port
    }

    func (this *Instance) String() string {
    return this.host + ":" + strconv.Itoa(this.port)
    }

  • random.go 模拟负载均衡,随机算法实现

    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
    package balance

    import (
    "errors"
    "math/rand"
    "time"
    )

    type RandomBalance struct{}

    // init方法 包被引用时调用
    func init() {
    RegisterBalance("random", &RandomBalance{})
    }

    func (this *RandomBalance) DoBalance(insts []*Instance) (inst *Instance, err error) {
    lens := len(insts)
    if lens == 0 {
    err = errors.New("Instance is nil")
    return
    }
    rand.Seed(time.Now().Unix())
    index := rand.Intn(lens)
    inst = insts[index]
    return
    }

  • roundrobin.go 模拟负载均衡,轮训算法实现

    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 balance

    import (
    "errors"
    "fmt"
    )

    // init方法 包被引用时调用
    func init() {
    RegisterBalance("roundrobin", &RoundRobinBalance{})
    }

    type RoundRobinBalance struct {
    index int
    }

    func (this *RoundRobinBalance) DoBalance(insts []*Instance) (inst *Instance, err error) {
    lens := len(insts)
    if lens == 0 {
    err = errors.New("Instance is nil")
    return
    }

    if this.index >= lens {
    this.index = 0
    fmt.Println("一次轮训")
    }
    inst = insts[this.index]
    this.index += 1
    return
    }

  • mgr.go 对Balance接口实现的管理和注册

    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
    33
    34
    35
    36
    package balance

    import "fmt"

    // 声明一个BalanceMgr类型的变量,用来对外暴露注册
    var (
    mgr = BalanceMgr{
    // 这里要注意初始化BalanceMgr结构体的map
    allBalancer: make(map[string]Balance),
    }
    )

    type BalanceMgr struct {
    allBalancer map[string]Balance
    }

    // 注册实现Balance接口的结构体
    func (this *BalanceMgr) registerBalance(name string, b Balance) {
    this.allBalancer[name] = b
    }

    func RegisterBalance(name string, b Balance) {
    mgr.registerBalance(name, b)
    }

    // 调用对应name的Balance实现类,处理传入的实例slice
    func DoBalance(name string, insts []*Instance) (inst *Instance, err error) {
    b, ok := mgr.allBalancer[name]
    if !ok {
    err = fmt.Errorf("Not Fuond %s Balance", name)
    }

    inst, err = b.DoBalance(insts)
    return
    }

  • hash.go 模拟负载均衡,一致性hash,对Balance接口的实现 (golang hash值的获取方法)

    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
    package main

    import (
    "fmt"
    "go_dev/day6/example7/balance"
    "hash/crc32"
    "math/rand"
    )

    func init() {
    balance.RegisterBalance("hash", &HashBalance{})
    }

    type HashBalance struct{}

    func (this *HashBalance) DoBalance(insts []*balance.Instance) (inst *balance.Instance, err error) {
    defKey := fmt.Sprintf("%d", rand.Int())
    lens := len(insts)
    if lens == 0 {
    err = fmt.Errorf("not backed instance")
    return
    }
    // 计算hash值
    crcTable := crc32.MakeTable(crc32.IEEE)
    hashVal := crc32.Checksum([]byte(defKey), crcTable)
    // 这里hashVal是uint32的类型 需要转成int进行取余
    index := int(hashVal) % lens
    inst = insts[index]
    return
    }

  • main.go 模拟收到请求后,进行请求的分发

    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    package main

    import (
    "fmt"
    "go_dev/day6/example7/balance"
    "math/rand"
    "os"
    "time"
    )

    func main() {
    var insts []*balance.Instance
    rand.Seed(time.Now().Unix())
    // 创建一组机器实例
    for i := 0; i < 10; i++ {
    host := fmt.Sprintf("192.168.%d.%d", rand.Intn(255), rand.Intn(254)+1)
    port := 8888
    one := balance.NewInstance(host, port)
    insts = append(insts, one)
    }

    balanceName := "random"
    // 从控制台获取输入参数
    if len(os.Args) > 1 {
    balanceName = os.Args[1]
    }

    fmt.Printf("use %s balance\n", balanceName)

    // 模拟负载均衡
    for {
    inst, err := balance.DoBalance(balanceName, insts)
    if err != nil {
    fmt.Printf("do balance err:%s\n", err)
    continue
    }
    fmt.Printf("%v\n", inst)
    time.Sleep(time.Second)
    }
    }

    文章中并无实际业务代码,仅是对golang接口的练习,和对负载均衡的简单模拟

Go使用redis

github地址:
https://github.com/garyburd/redigo

文档地址:
http://godoc.org/github.com/garyburd/redigo/redis

获取:

1
go get github.com/garyburd/redigo/redis

连接redis:

1
2
3
4
5
6
7
8
9
10
func connectRedis() {
// 连接redis
conn, err := redis.Dial("tcp", "127.0.0.1:6379")
if err != nil {
fmt.Printf("connect redis error:%s\n", err)
return
}
defer conn.Close()
}

读写:

这里写入的值不会过期

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

func readWriteRedis() {
// 链接redis
conn, err := redis.Dial("tcp", "127.0.0.1:6379")
if err != nil {
fmt.Printf("connect redis error:%s\n", err)
}
defer conn.Close()
// 写入一个key为“mykey”,value为10的键值对 这里写入的键值对永远不会过期
_, err = conn.Do("SET", "mykey", 10)
if err != nil {
fmt.Printf("redis set failed:%s\n", err)
return
}
v, err := redis.Int(conn.Do("GET", "mykey"))
if err != nil {
fmt.Printf("redis get failed:%s\n", err)
return
}
fmt.Printf("get mykey value:%d\n", v)
}

func main() {
readWriteRedis()
}
---------------------
get mykey value:10

如何设置过期呢,可以使用SET的附加参数:

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
33
34
35
36
37
38
func readWriteRedisEx() {
// 链接redis
conn, err := redis.Dial("tcp", "127.0.0.1:6379")
if err != nil {
fmt.Printf("connect redis error:%s\n", err)
}
defer conn.Close()
// 写入一个Key并设置它的过期时间
_, err = conn.Do("SET", "extime", 5, "EX", "5")
if err != nil {
fmt.Printf("redis set failed:%s\n", err)
return
}
v, err := redis.Int(conn.Do("GET", "extime"))
if err != nil {
fmt.Printf("redis get failed:%s\n", err)
return
}
fmt.Printf("get mykey value:%d\n", v)
// 睡眠5秒再次读取
time.Sleep(time.Second * 6)

v, err = redis.Int(conn.Do("GET", "extime"))
if err != nil {
// 由于key设置了超时时间是5秒 这里无法读到key的值
fmt.Printf("redis get failed:%s\n", err)
return
}
fmt.Printf("get mykey value:%d\n", v)
}

func main() {
readWriteRedisEx()
}

---------------------------------
get mykey value:5
redis get failed:redigo: nil returned

批量写入 读取

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
func batchReadWriteRedis() {
conn, err := redis.Dial("tcp", "127.0.0.1:6379")
if err != nil {
fmt.Printf("connect redis error:%s\n", err)
return
}
defer conn.Close()
// 批量设置key
_, err = conn.Do("MSET", "mykey1", "key1", "mykey2", "key2", "mykey3", "key3")
if err != nil {
fmt.Printf("redis mset failed:%s\n", err)
return
}
// 批量读取
v, err := redis.Strings(conn.Do("MGET", "mykey1", "mykey2", "mykey3"))
if err != nil {
fmt.Printf("redis mget faild:%s\n", err)
return
}
for index, val := range v {
fmt.Printf("the %d value is:%s\n", index, val)
}
}

func main() {
batchReadWriteRedis()
}
-------------------------------------
the 0 value is:key1
the 1 value is:key2
the 2 value is:key3

使用redis连接池,EXISTS检测值是否存在

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import (
"encoding/json"
"fmt"
"time"

"github.com/garyburd/redigo/redis"
)

var pool *redis.Pool

func init() {
pool = &redis.Pool{
// 最大空闲连接数
MaxIdle: 16,
//池在给定时间分配的最大连接数。当为零时,池中的连接数没有限制。
MaxActive: 0,
//在此期间保持空闲后关闭连接。 如果该值为零,则不关闭空闲连接。 应用程序应将超时设置为小于服务器超时的值。
IdleTimeout: 300,
// Dial是应用程序提供的功能,用于创建和配置连接。 从Dial返回的连接不能处于特殊状态(订阅pubsub通道,事务已启动,...)。
Dial: func() (redis.Conn, error) {
return redis.Dial("tcp", "127.0.0.1:6379")
},
}
}

// 使用连接池
func existsKey() {
// 从连接池中获取连接
conn := pool.Get()
// 用完后把连接放回连接池
defer conn.Close()
b, err := redis.Bool(conn.Do("EXISTS", "mykey"))
if err != nil {
fmt.Printf("redis exists error:%s\n", err)
return
}
if b {
fmt.Println("key exist")
} else {
fmt.Println("Key does not exist")
}
}

func main() {
existsKey()
}
----------------------------
key exist

把json写到redis

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import (
"encoding/json"
"fmt"
"time"

"github.com/garyburd/redigo/redis"
)

var pool *redis.Pool

func init() {
pool = &redis.Pool{
// 最大空闲连接数
MaxIdle: 16,
//池在给定时间分配的最大连接数。当为零时,池中的连接数没有限制。
MaxActive: 0,
//在此期间保持空闲后关闭连接。 如果该值为零,则不关闭空闲连接。 应用程序应将超时设置为小于服务器超时的值。
IdleTimeout: 300,
// Dial是应用程序提供的功能,用于创建和配置连接。 从Dial返回的连接不能处于特殊状态(订阅pubsub通道,事务已启动,...)。
Dial: func() (redis.Conn, error) {
return redis.Dial("tcp", "127.0.0.1:6379")
},
}
}

// 把json写到redis
func jsonToRedis() {
key := "stu01"
imap := map[string]string{"username": "张三", "age": "10", "phone": "13773943000"}
value, err := json.Marshal(imap)
if err != nil {
fmt.Println("map to json error")
return
}
conn := pool.Get()
defer conn.Close()
_, err = conn.Do("SET", key, value)
if err != nil {
fmt.Println("set key error")
return
}

v, err := redis.String(conn.Do("GET", key))
if err != nil {
fmt.Println("get key error")
return
}
fmt.Println("value is:", v)
}
------------------------------
value is: {"age":"10","phone":"13773943000","username":"张三"}

为已存在的key设置过期时间

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
33
34
35
36
37
38
39
import (
"encoding/json"
"fmt"
"time"

"github.com/garyburd/redigo/redis"
)

var pool *redis.Pool

func init() {
pool = &redis.Pool{
// 最大空闲连接数
MaxIdle: 16,
//池在给定时间分配的最大连接数。当为零时,池中的连接数没有限制。
MaxActive: 0,
//在此期间保持空闲后关闭连接。 如果该值为零,则不关闭空闲连接。 应用程序应将超时设置为小于服务器超时的值。
IdleTimeout: 300,
// Dial是应用程序提供的功能,用于创建和配置连接。 从Dial返回的连接不能处于特殊状态(订阅pubsub通道,事务已启动,...)。
Dial: func() (redis.Conn, error) {
return redis.Dial("tcp", "127.0.0.1:6379")
},
}
}

func setExpire() {
conn := pool.Get()
defer conn.Close()
// 这里单位是秒
_, err := conn.Do("EXPIRE", "mykey", 5)
if err != nil {
fmt.Println("redus expire error")
return
}
}

func main() {
setExpire()
}

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package main

import (
"fmt"
"reflect"
)

type FooIF interface {
DoSomething()
DoSomethingWithArg(a string)
DoSomethingWithUnCertenArg(a ... string)
}

type Foo struct {
A int
B string
C struct {
C1 int
}
}

func (f *Foo) DoSomething() {
fmt.Println(f.A, f.B)
}

func (f *Foo) DoSomethingWithArg(a string) {
fmt.Println(f.A, f.B, a)
}

func (f *Foo) DoSomethingWithUnCertenArg(a ... string) {
fmt.Println(f.A, f.B, a[0])
}

func (f *Foo) returnOneResult() int {
return 2
}

func main() {
var simpleObj Foo
var pointer2obj = &simpleObj
var simpleIntArray = [3]int{1, 2, 3}
var simpleMap = map[string]string{
"a": "b",
}
var simpleChan = make(chan int, 1)
var x uint64
var y uint32

varType := reflect.TypeOf(simpleObj)
varPointerType := reflect.TypeOf(pointer2obj)

// 对齐之后要多少容量
fmt.Println("Align: ", varType.Align())
// 作为结构体的`field`要对其之后要多少容量
fmt.Println("FieldAlign: ", varType.FieldAlign())
// 叫啥
fmt.Println("Name: ", varType.Name())
// 绝对引入路径
fmt.Println("PkgPath: ", varType.PkgPath())
// 实际上用了多少内存
fmt.Println("Size: ", varType.Size())
// 到底啥类型的
fmt.Println("Kind: ", varType.Kind())

// 有多少函数
fmt.Println("NumMethod: ", varPointerType.NumMethod())

// 通过名字获取一个函数
m, success := varPointerType.MethodByName("DoSomethingWithArg")
if success {
m.Func.Call([]reflect.Value{
reflect.ValueOf(pointer2obj),
reflect.ValueOf("sad"),
})
}

// 通过索引获取函数
m = varPointerType.Method(1)
m.Func.Call([]reflect.Value{
reflect.ValueOf(pointer2obj),
reflect.ValueOf("sad2"),
})

// 是否实现了某个接口
fmt.Println("Implements:", varPointerType.Implements(reflect.TypeOf((*FooIF)(nil)).Elem()))

// 看看指针多少bit
fmt.Println("Bits: ", reflect.TypeOf(x).Bits())

// 查看array, chan, map, ptr, slice的元素类型
fmt.Println("Elem: ", reflect.TypeOf(simpleIntArray).Elem().Kind())

// 查看Array长度
fmt.Println("Len: ", reflect.TypeOf(simpleIntArray).Len())

// 查看结构体field
fmt.Println("Field", varType.Field(1))

// 查看结构体field
fmt.Println("FieldByIndex", varType.FieldByIndex([]int{2, 0}))

// 查看结构提field
fi, success2 := varType.FieldByName("A")
if success2 {
fmt.Println("FieldByName", fi)
}

// 查看结构体field
fi, success2 = varType.FieldByNameFunc(func(fieldName string) bool {
return fieldName == "A"
})
if success2 {
fmt.Println("FieldByName", fi)
}

// 查看结构体数量
fmt.Println("NumField", varType.NumField())

// 查看map的key类型
fmt.Println("Key: ", reflect.TypeOf(simpleMap).Key().Name())

// 查看函数有多少个参数
fmt.Println("NumIn: ", reflect.TypeOf(pointer2obj.DoSomethingWithUnCertenArg).NumIn())

// 查看函数参数的类型
fmt.Println("In: ", reflect.TypeOf(pointer2obj.DoSomethingWithUnCertenArg).In(0))

// 查看最后一个参数,是否解构了
fmt.Println("IsVariadic: ", reflect.TypeOf(pointer2obj.DoSomethingWithUnCertenArg).IsVariadic())

// 查看函数有多少输出
fmt.Println("NumOut: ", reflect.TypeOf(pointer2obj.DoSomethingWithUnCertenArg).NumOut())

// 查看函数输出的类型
fmt.Println("Out: ", reflect.TypeOf(pointer2obj.returnOneResult).Out(0))

// 查看通道的方向, 3双向。
fmt.Println("ChanDir: ", int(reflect.TypeOf(simpleChan).ChanDir()))

// 查看该类型是否可以比较。不能比较的slice, map, func
fmt.Println("Comparable: ", varPointerType.Comparable())

// 查看类型是否可以转化成另外一种类型
fmt.Println("ConvertibleTo: ", varPointerType.ConvertibleTo(reflect.TypeOf("a")))

// 该类型的值是否可以另外一个类型
fmt.Println("AssignableTo: ", reflect.TypeOf(x).AssignableTo(reflect.TypeOf(y)))
}

goroute详解

  • 获取和设置当前runtime可用的最大核心数:
    1
    2
    3
    4
    5
    6
    7
    func main() {
    // 返回当前主机的cpu核心数
    num := runtime.NumCPU()
    // 设置当前runtime可用的最大核心数
    runtime.GOMAXPROCS(num)
    fmt.Printf("max cup :%v\n", num)
    }

多线程:

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
// 多线程 编译时建议带上参数-race,可以帮助检测函数中是否有锁竞争  go build -race xx/xxx/xxx/main

var (
m = make(map[int]int)
lock sync.Mutex
)

func calc(c int) {
num := 1
for i := 1; i < c; i++ {
num *= i
}

lock.Lock()
m[c] = num
lock.Unlock()
}

func main() {
for i := 0; i < 10; i++ {
go calc(i)
}
time.Sleep(time.Second)
lock.Lock()
for k, v := range m {
fmt.Printf("k:%v,v:%v\n", k, v)
}
lock.Unlock()
}

channel的使用:

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// 如果存放的元素超过了channel定义的长度,则会处于阻塞状态,直到channel内的元素被取出

func test1() {
var m chan int
m = make(chan int, 10)
m <- 1
m <- 2
m <- 3

a := <-m
fmt.Printf("a:%d\n", a)
}

func test2() {
var c chan map[string]string
c = make(chan map[string]string, 10)
m := make(map[string]string, 10)
m["m1"] = "01"
m["m2"] = "02"

c <- m

v := <-c
fmt.Printf("v:%v\n", v)

}

func test3() {
var c chan student
c = make(chan student, 10)
s := student{
name: "张三",
}
c <- s

v := <-c
fmt.Printf("v:%v\n", v)

}

func main() {
test1()
test2()
test3()
}

在gorutine中使用channel:

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
func write(c chan int) {
// 如果存放的元素超过了channel定义的长度,则会处于阻塞状态,直到channel内的元素被取出
for i := 0; i < 100; i++ {
c <- i
fmt.Println("put data:", i)
}
}

func read(c chan int) {
for {
var b int
b = <-c
fmt.Println("pop data:", b)
time.Sleep(time.Millisecond * 100)
}
}

func main() {
var c chan int
c = make(chan int, 10)
go write(c)
go read(c)

time.Sleep(time.Second * 10)

}

多个goroutine并发:

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
func initData(c chan int) {
for i := 0; i < 10000; i++ {
c <- i
}
close(c)
}

func calc(takeChan chan int, result chan int, exit chan bool) {
flag := true
for v := range takeChan {

for i := 2; i < v; i++ {
if v%i == 0 {
flag = false
break
}
}
if flag {
result <- v
}
flag = true
}
exit <- true
fmt.Println("exit-----------------------------------------------------")
}

func read(result chan int) {
for v := range result {
fmt.Println("result:", v)
}
}

func main() {
var intChan chan int
var resultChan chan int
var exitChan chan bool
intChan = make(chan int, 1000)
resultChan = make(chan int, 1000)
exitChan = make(chan bool, runtime.NumCPU())
go initData(intChan)
for i := 0; i < runtime.NumCPU(); i++ {
go calc(intChan, resultChan, exitChan)
go read(resultChan)
}
for i := 0; i < runtime.NumCPU(); i++ {
fmt.Printf("**************************wait goroute:%d************************\n", i)
<-exitChan
}
close(resultChan)
close(exitChan)
}

channel使用完要关闭:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func main() {
var c chan int
c = make(chan int, 10)
for i := 0; i < 10; i++ {
c <- i
}

close(c)
for {
v, ok := <-c
if ok == false {
fmt.Println("channel is colse!")
break
}
fmt.Println(v)
}
}

```

### select关键字的使用:

func main() {
var ch chan int
var ch2 chan int
ch = make(chan int, 10)
ch2 = make(chan int, 10)
go func() {
for i := 0; i < 10; i++ {
ch <- i
ch2 <- i * i
time.Sleep(time.Second)
}
}()

for {
    select {
    case v := <-ch:
        fmt.Println(v)
    case v := <-ch2:
        fmt.Println(v)
    default:
        fmt.Println("get data timeout")
        time.Sleep(time.Second)
    }
}

}

```

类型断言

类型断言,由于接口是一般类型,不知道具体类型,如果要转成具体类型
可以采用以下方法进行转换:

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
func test1() {
var a interface{}
var b int = 10
a = b
fmt.Printf("a type is %T value is %d\n", a, a)
// 断言
c, ok := a.(int)
if ok == false {
fmt.Println("conversion fail")
return
}
fmt.Printf("c type is %T value is %d\n", c, c)
}

func main() {
test1()
}
------------
a type is int value is 10
c type is int value is 10



type Student struct{}

func assertion(item ...interface{}) {
for i, v := range item {
switch v.(type) {
case bool:
fmt.Printf("%d param is bool value is %v\n", i, v)
case string:
fmt.Printf("%d param is string value is %v\n", i, v)
case float32, float64:
fmt.Printf("%d param is float value is %v\n", i, v)
case int, int32, int64:
fmt.Printf("%d param is int value is %v\n", i, v)
case Student:
fmt.Printf("%d param is Student value is %v\n", i, v)
case *Student:
fmt.Printf("%d param is Student Pointer value is %v\n", i, v)
default:
fmt.Printf("%d param type is unknown value is %v\n", i, v)
}
}
}

func test2() {
var stu Student
assertion(true, stu, 1, 1.2, "test", &Student{})
}

func main() {
test2()
}
--------------
0 param is bool value is true
1 param is Student value is {}
2 param is int value is 1
3 param is float value is 1.2
4 param is string value is test
5 param is Student Pointer value is &{}

实现sort.Interface接口

任何实现了 sort.Interface 的类型(一般为集合),均可使用该包中的方法进行排序。 这些方法要求集合内列出元素的索引为整数。

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
type Student struct {
Name string
Age int
}

type StudentArray []Student

// Len 为集合内元素的总数
func (this StudentArray) Len() int {
return len(this)
}

// Less 返回索引为 i 的元素是否应排在索引为 j 的元素之前。
func (this StudentArray) Less(i, j int) bool {
return this[i].Age < this[j].Age
}

// Swap 交换索引为 i 和 j 的元素
func (this StudentArray) Swap(i, j int) {
this[i], this[j] = this[j], this[i]
}

func main() {
var stuArr StudentArray
for i := 0; i < 15; i++ {
stu := Student{
Name: fmt.Sprintf("stu%d", rand.Intn(100)),
Age: rand.Intn(100),
}
stuArr = append(stuArr, stu)
}
fmt.Println("排序前:")
for _, v := range stuArr {
fmt.Printf("name:%v,age:%d\n", v.Name, v.Age)
}

sort.Sort(stuArr)
fmt.Println("排序后:")
for _, v := range stuArr {
fmt.Printf("name:%v,age:%d\n", v.Name, v.Age)
}
}
------------------------
排序前:
name:stu81,age:87
name:stu47,age:59
name:stu81,age:18
name:stu25,age:40
name:stu56,age:0
name:stu94,age:11
name:stu62,age:89
name:stu28,age:74
name:stu11,age:45
name:stu37,age:6
name:stu95,age:66
name:stu28,age:58
name:stu47,age:47
name:stu87,age:88
name:stu90,age:15
排序后:
name:stu56,age:0
name:stu37,age:6
name:stu94,age:11
name:stu90,age:15
name:stu81,age:18
name:stu25,age:40
name:stu11,age:45
name:stu47,age:47
name:stu28,age:58
name:stu47,age:59
name:stu95,age:66
name:stu28,age:74
name:stu81,age:87
name:stu87,age:88
name:stu62,age:89

接口

Interface类型可以定义一组方法,但是这些不需要实现。并且interface不能包含任何变量。

如果一个变量实现了String()这个方法,那么fmt.Println默认会调用这个变量的String()进行输出。(对比java中的重写toString()方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
type student struct {
name string
age int
}

func (s student) String() string {
str := fmt.Sprintf("name:[%s],age:[%d]\n", s.name, s.age)
return str
}

func main() {
var s student = student{
name: "张三",
age: 18,
}
fmt.Println(s)
}

接口实现

Golang中的接口,不需要显示的实现。只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。因此,golang中没有implement类似的关键字
如果一个变量含有了多个interface类型的方法,那么这个变量就实现了多个接口。
如果一个变量只含有了1个interface的方部分方法,那么这个变量没有实现这个接口。

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
33
34
35
36
37
type Person interface {
eat()
sleep()
run()
}

// Student实现了Person接口中的所有方法即Student实现了Person接口
type Student struct {
Name string
Age int
}

func (s Student) eat() {
fmt.Printf("%s eat!\n", s.Name)
}

func (s Student) sleep() {
fmt.Printf("%s sleep!\n", s.Name)
}

func (s Student) run() {
fmt.Printf("%s run!\n", s.Name)
}

func main() {
var s Student = Student{
Name: "张三",
Age: 18,
}
s.eat()
s.sleep()
s.run()
}
-----------------------
张三 eat!
张三 sleep!
张三 run!

接口嵌套

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
type Person interface {
eat()
sleep()
run()
}
type Students interface {
Person
learn()
exam()
}

type Student struct {
Name string
Age int
}

func (s Student) eat() {
fmt.Printf("%s 吃饭!\n", s.Name)
}

func (s Student) sleep() {
fmt.Printf("%s 睡觉!\n", s.Name)
}

func (s Student) run() {
fmt.Printf("%s 运动!\n", s.Name)
}

func (s Student) learn() {
fmt.Printf("%s 学习!\n", s.Name)
}

func (s Student) exam() {
fmt.Printf("%s 考试!\n", s.Name)
}

func main() {
var s Student = Student{
Name: "张三",
Age: 18,
}
s.eat()
s.sleep()
s.run()
s.learn()
s.exam()
}
----------------
张三 吃饭!
张三 睡觉!
张三 运动!
张三 学习!
张三 考试!

多态

一种事物的多种形态,都可以按照统一的接口进行操作

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
type Persons interface {
eat()
sleep()
run()
}
type Students interface {
Persons
learn()
exam()
}

type Person struct {
Name string
Age int
}

type Student struct {
Name string
Age int
}

func (s Student) eat() {
fmt.Printf("%s 吃饭!\n", s.Name)
}

func (s Student) sleep() {
fmt.Printf("%s 睡觉!\n", s.Name)
}

func (s Student) run() {
fmt.Printf("%s 运动!\n", s.Name)
}

func (s Student) learn() {
fmt.Printf("%s 学习!\n", s.Name)
}

func (s Student) exam() {
fmt.Printf("%s 考试!\n", s.Name)
}

func (p Person) eat() {
fmt.Printf("%s 吃饭!\n", p.Name)
}

func (p Person) sleep() {
fmt.Printf("%s 睡觉!\n", p.Name)
}

func (p Person) run() {
fmt.Printf("%s 运动!\n", p.Name)
}

func main() {
var ps Persons
var s Student = Student{
Name: "张三",
Age: 18,
}
var p Person = Person{
Name: "李四",
Age: 18,
}
// 这里接口Persons可以是Person 也可以是Student
ps = s
ps.eat()
ps.run()
ps.sleep()

ps = p
ps.eat()
ps.run()
ps.sleep()

}
--------------------
张三 吃饭!
张三 运动!
张三 睡觉!
李四 吃饭!
李四 运动!
李四 睡觉!

单向链表的遍历、新增、删除操作

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
type linkedlist struct {
value string
next *linkedlist
}

// 遍历链表
func traversing(link *linkedlist) {
fmt.Printf("%s\n", (*link).value)
if link.next != nil {
traversing(link.next)
}
}

// 在链表最后插入一个元素
func insertLink(root, target *linkedlist) *linkedlist {
if root.next != nil {
insertLink(root.next, target)
}

if root.next == nil {
root.next = target
}

return root
}

// 删除指定value节点
func delLink(root *linkedlist, name string) {
var prev *linkedlist = root
for root != nil {
if root.value == name {
prev.next = root.next
break
}
prev = root
root = root.next
}
}

func test1() {
link := &linkedlist{
value: "1",
}

s := &linkedlist{
value: "2",
}

s1 := &linkedlist{
value: "3",
}

link.next = s
s.next = s1
traversing(link)
}

func test2() {
var root *linkedlist = &linkedlist{
value: "root1",
}

var p *linkedlist = root

for i := 1; i < 10; i++ {
var s *linkedlist = &linkedlist{
value: fmt.Sprintf("s%d", i),
}
fmt.Printf("%v\n", s)
p.next = s
p = s
}
traversing(root)
delLink(root, "s3")
}

func test3() {
var root *linkedlist = &linkedlist{
value: "root1",
}

for i := 1; i < 10; i++ {
var s *linkedlist = &linkedlist{
value: fmt.Sprintf("s%d", i),
}
insertLink(root, s)
}
traversing(root)
fmt.Printf("delete\n")
delLink(root, "s3")
traversing(root)
}

func main() {
test3()
}

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
33
34
35
36
37
38
39
40
41
42
type Node struct {
Value int
Left, Right *Node
}

func createNode(value int) *Node {
return &Node{
Value: value,
}
}

func traversing(root *Node) {

if root == nil {
return
}
// 中序遍历
traversing(root.Left)
fmt.Printf("%d\n", root.Value)
traversing(root.Right)

}

func main() {
var root *Node = createNode(3)
root.Left = createNode(1)
root.Right = createNode(5)
root.Left.Left = createNode(0)
root.Left.Right = createNode(2)
root.Right.Left = createNode(4)
root.Right.Right = createNode(6)

traversing(root)
}
------------------
0
1
2
3
4
5
6

上述代码在创建并初始化的二叉树结构如下图
Go语言创建一个简单的二叉树