go语言处理数据
go语言处理json数据
go语言数据对象 -> json数据
- 结构体 struct -- 将结构体转成 json ,结构体成员变量第一个字母必须大写,只有字段首字母大写的才会被转换
- 数组 array 、切片 slice -- slice / array 转换成json 数据
- 集合 map --集合map转换成 json 数据 , map 的 key 必须是string类型,这是json要求的
- 上述数据结构组合在一起
使用struct tag的时候,几个注意点:
- 1、tag中标识的名称将称为json数据中key的值
- 2、tag可以设置为`json:"-"`来表示本字段不转换为json数据,即使这个字段名首字母大写
- 如果想要json key的名称为字符"-",则可以特殊处理`json:"-,"`,也就是加上一个逗号
- 3、如果tag中带有,omitempty选项,那么如果这个字段的值为0值,即false、0、""、nil等,这个字段将不会转换到json中
- 4、如果字段的类型为bool、string、int类、float类,而tag中又带有,string选项,那么这个字段的值将转换成json字符串
goToJson.go
/* author:qb date: 2020年11月 8日 20:01:10 what: go数据对象 -> json数据 */ package main import ( "encoding/json" //json包 "fmt" ) //将结构体转成 json ,结构体成员变量第一个字母必须大写,只有字段首字母大写的才会被转换 type Post struct { Name string ShowName string Des string } type Stu struct { Info map[string]string `json:"个人信息"` Hobby []string `json:"爱好"` Enable bool `json:"是否启用"` test []string `json:"tttt"` } func main() { //将结构体转成 json post := &Post{"xiaozhu", "hello xiaozhu", "this is a name"} b, err := json.MarshalIndent(post, "", "\t") //一个字段占一行 if err != nil { fmt.Println(nil) } fmt.Println(string(b)) //slice / array 转换成json 数据 post2 := []string{"apple", "pen", "penapple"} b2, err2 := json.Marshal(post2) if err2 != nil { fmt.Println(nil) } fmt.Println(string(b2)) //集合map转换成 json 数据 , map 的 key 必须是string类型,这是json要求的 post3 := map[string]string{"name": "xiaozhu", "age": "13", "height": "168"} b3, err3 := json.MarshalIndent(post3, "", "\t") if err3 != nil { fmt.Println(err) } fmt.Println(string(b3)) //组合在一起使用 var stu Stu stu.Enable = true stu.Hobby = []string{"running", "basketball", "football"} stu.Info = map[string]string{ "name": "xiaozhu", "age": "24", "height": "178"} bs, errs := json.MarshalIndent(&stu, "", "\t") //bs, errs := json.Marshal(&stu) if errs != nil { fmt.Println(errs) } fmt.Println(string(bs)) }
json数据 -> go语言数据对象
解析json数据到struct(结构已知)
- 根据已知json文件进行分析,定义struct
- 使用os 打开json数据文件
- 读取json文件,将数据保存下来
- 解析jsondata 将数据放到 结构体Post中
- 使用解析出来的数据
data.json
{ "id": 1, "content": "hello world", "author": { "id": 2, "name": "userA" }, "published": true, "label": [], "nextPost": null, "comments": [{ "id": 3, "content": "good post1", "author": "userB" }, { "id": 4, "content": "good post2", "author": "userC" } ] }
jsonToGo.go
/* author:qb date: 2020年11月 8日 21:12:01 what: json数据 -> go数据对象 //对于已知json结构进行解析 */ package main import ( "encoding/json" "fmt" "io/ioutil" "os" ) //1.根据已知json文件进行分析,定义struct type Post struct { Id int `json:"id"` Content string `json:"content"` Author *Author `json:"author"` Published bool `json:"published"` Label []string `json:"label"` NextPost *Post `json:"nextPost"` Comments []*Comments `json:"comments"` } type Author struct { Id int `json:"id"` Name string `json:"name"` } type Comments struct { Id int `json:"id"` Content string `json:"content"` Author string `json:"author"` } func main() { //2.使用os 打开json数据文件 fh, err := os.Open("./data.json") if err != nil { fmt.Println(err) return } defer fh.Close() //3.读取json文件,将数据保存下来 jsondata, err := ioutil.ReadAll(fh) if err != nil { fmt.Println(err) return } //fmt.Println(string(jsondata)) //4.解析jsondata 将数据放到 结构体Post中 var post Post err = json.Unmarshal(jsondata, &post) if err != nil { fmt.Println(err) return } //5.使用解析出来的数据 fmt.Println(post) fmt.Println(post.Author.Id) fmt.Println(post.Author.Name) fmt.Println(post.Comments[0].Id) fmt.Println(post.Comments[0].Author) fmt.Println(post.Comments[0].Content) }
解析json数据到struct(结构未知)
- 根据已知json文件进行分析,定义struct
- 读取json文件,将数据保存下来
- 解析jsondata 将数据放到 结构体Post中
- 使用解析出来的数据 此时还是 map[string]interface{}
- 解析成可以控制的数据
/* author:qb date: 2020年11月 8日 21:44:39 what: json数据 -> go数据对象 //对于未知json结构进行解析 */ package main import ( "encoding/json" "fmt" "io/ioutil" "os" ) //1.根据已知json文件进行分析,定义struct func main() { //1.使用os 打开json数据文件 fh, err := os.Open("./data.json") if err != nil { fmt.Println(err) return } defer fh.Close() //2.读取json文件,将数据保存下来 jsondata, err := ioutil.ReadAll(fh) if err != nil { fmt.Println(err) return } //fmt.Println(string(jsondata)) //3.解析jsondata 将数据放到 结构体Post中 var unknown interface{} err = json.Unmarshal(jsondata, &unknown) if err != nil { fmt.Println(err) return } //4.使用解析出来的数据 此时还是 map[string]interface{} //fmt.Println(unknown) //5.解析成可以控制的数据 m := unknown.(map[string]interface{}) for k, v := range m { switch vv := v.(type) { case string: fmt.Println(k, "type:string", v) fmt.Println("--------------------") case float64: fmt.Println(k, "type:float64", v) fmt.Println("--------------------") case bool: fmt.Println(k, "type:bool", v) fmt.Println("--------------------") case map[string]interface{}: fmt.Println(k, "type:map[string]interface{}", v) for kk, value := range vv { fmt.Println(kk, ":", value) } fmt.Println("--------------------") case []interface{}: fmt.Println(k, "type:[]interface{}", v) for key, val := range vv { switch hh := val.(type) { case map[string]interface{}: fmt.Println(key, ":", val) for hk, hv := range hh { fmt.Println(hk, ":", hv) } fmt.Println("========") default: fmt.Println("========", hh) } } fmt.Println("--------------------") default: fmt.Println(k, "type:<nil>", v) } } //test := map[string]string{"name": "qb", "age": "20"} //fmt.Println(test) //fmt.Println(test["name"]) }
simplejson使用
未完待续。。。
go语言处理protobuf
可以参考如下链接:https://blog.csdn.net/weixin_42117918/article/details/88920221
- 现在最新的go语言请保持GOPATH的干净,整洁,不要将自己的源代码放到src目录里面
- 可以使用安装软件时候的默认GOPATH和GOROOT
- go语言打开modules管理的时候,注意,引入包的时候都是通过modules引入的
- 同一个目录里面的所有文件,包名都应该是一致的
go env -w GO111MODULE=on //打开模块 go env -w GOPROXY=https://goproxy.cn,direct //启用代理 go env -w GOSUMDB=off //关闭
go语言安装protobuf环境
1、window 环境/linux 环境 在该 https://github.com/protocolbuffers/protobuf/releases 网站上下载压缩包,解压出的 可执行程序(bin/可执行程序)放到 $GOPATH/bin/目录下
2、执行 go get github.com/golang/protobuf ,
执行 go get -u github.com/golang/protobuf/protoc-gen-go(gopath的bin目录会生成protoc-gen-go.exe)
3、开始使用protobuf
目录结构为:
test.proto
syntax="proto3"; //版本号 package mypro; //包名 enum ClassName{ //枚举 class1=0; //标号 必须从 0开始 class2=1; class3=2; } message Student{ //消息,对应于Go的结构体 string name=1; //1:标号,唯一 即可(相当于数据库中的Id,不一定要从1 ,2的顺序依次排列。) int32 age=2; //必须指定整型的范围,如int32,int64 string address=3; ClassName cn=4; } message Students{ repeated Student person=1; // repeated 修饰,相当于Go中切片 string school=2; }
- 执行:protoc --go_out=. *.proto , 会生成 .pb.go文件
main.go
package main import ( "fmt" "github.com/golang/protobuf/proto" "mypro.com/mypro" //引入的proto的包 , go语言中,一个目录里面的所有文件都应设置成一个包 ) func main() { s1 := &mypro.Student{} //第一个学生信息 s1.Name = "jz01" s1.Age = 23 s1.Address = "cq" s1.Cn = mypro.ClassName_class2 //枚举类型赋值 ss := &mypro.Students{} ss.Person = append(ss.Person, s1) //将第一个学生信息添加到Students对应的切片中 s2 := &mypro.Student{} //第二个学生信息 s2.Name = "jz02" s2.Age = 25 s2.Address = "cd" s2.Cn = mypro.ClassName_class3 ss.Person = append(ss.Person, s2) //将第二个学生信息添加到Students对应的切片中 ss.School = "cqu" fmt.Println("Students信息为:", ss) // Marshal takes a protocol buffer message // and encodes it into the wire format, returning the data. buffer, _ := proto.Marshal(ss) fmt.Println("序列化之后的信息为:", buffer) // Use UnmarshalMerge to preserve and append to existing data. data := &mypro.Students{} proto.Unmarshal(buffer, data) fmt.Println("反序列化之后的信息为:", data) }
- 在main.go的同级目录 执行 go mod init xxx , 模块化 如:go mod init mypro.com
- 在main.go 同级目录 执行 go build , 若执行成功,则正确解析protobuf
golang使用grpc
环境配置
在之前protobuf安装正确,切能正常使用的情况下
方法1
- go get -u google.golang.org/grpc
如果执行失败,可有设置golang 的代理
go env -w GOPROXY=https://goproxy.cn,direct
方法2
查看 https://blog.csdn.net/dubinyang/article/details/109079237
简单写一个grpc 的客户端和服务端
- proto文件 -- 使用 protoc --go_out=plugins=grpc:. xxx.proto
- client.go
- srv.go
- 服务端,和客户端 分开运行即可看到效果
目录结构为:
-------------------------------
| mygrpc
| ---------pb
| -------------test.proto
| ---------client.go
| ---------srv.go
-------------------------------
test.proto
syntax = "proto3"; // proto版本 package pb; // 指定包名,默认go中包名也是这个 // 定义Love服务 service Love { // 定义Confession方法 rpc Confession(Request) returns (Response) {} } // 请求 message Request { string name = 1; } // 响应 message Response { string result = 1; }
client.go
package main import ( "context" "log" "mygrpc.com/pb" "google.golang.org/grpc" ) func main() { // 连接grpc服务 conn, err := grpc.Dial(":8888", grpc.WithInsecure()) if err != nil { log.Fatal(err) } // 很关键 defer conn.Close() // 初始化客户端 c := pb.NewLoveClient(conn) // 发起请求 response, err := c.Confession(context.Background(), &pb.Request{Name: "Bob"}) if err != nil { log.Fatal(err) } log.Println(response.Result) }
srv.go
package main import ( "context" "log" "net" "google.golang.org/grpc" "mygrpc.com/pb" ) // 定义Love服务 type Love struct { } // 实现Love服务接口 func (l *Love) Confession(ctx context.Context, request *pb.Request) (*pb.Response, error) { resp := &pb.Response{} resp.Result = "your name is " + request.Name return resp, nil } func main() { // 监听8888端口 listen, err := net.Listen("tcp", ":8888") if err != nil { log.Fatal(err) } // 实例化grpc server s := grpc.NewServer() // 注册Love服务 pb.RegisterLoveServer(s, new(Love)) log.Println("Listen on 127.0.0.1:8888...") s.Serve(listen) }
- 启动2个终端(例如vscode),分别运行 服务器代码和客户端代码,执行看效果
单元测试
go test -v t_test.go -test.run TestFmt2 会调用TestFmt2
https://studygolang.com/articles/28209?fr=sidebar