go语言处理数据、基本通信以及环境配置 -- json,protobuf,grpc

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: go语言处理数据、基本通信以及环境配置 -- json,protobuf,grpc

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

 

 

 

 

 

 

 

 

 

相关文章
|
17天前
|
存储 Go 索引
go语言中数组和切片
go语言中数组和切片
26 7
|
16天前
|
Go 开发工具
百炼-千问模型通过openai接口构建assistant 等 go语言
由于阿里百炼平台通义千问大模型没有完善的go语言兼容openapi示例,并且官方答复assistant是不兼容openapi sdk的。 实际使用中发现是能够支持的,所以自己写了一个demo test示例,给大家做一个参考。
|
17天前
|
程序员 Go
go语言中结构体(Struct)
go语言中结构体(Struct)
92 71
|
16天前
|
存储 Go 索引
go语言中的数组(Array)
go语言中的数组(Array)
100 67
|
17天前
|
存储 Go
go语言中映射
go语言中映射
32 11
|
19天前
|
Go
go语言for遍历映射(map)
go语言for遍历映射(map)
29 12
|
18天前
|
Go 索引
go语言使用索引遍历
go语言使用索引遍历
26 9
|
18天前
|
Go 索引
go语言使用range关键字
go语言使用range关键字
24 7
|
18天前
|
Go 索引
go语言修改元素
go语言修改元素
25 6
|
8天前
|
Go 数据安全/隐私保护 UED
优化Go语言中的网络连接:设置代理超时参数
优化Go语言中的网络连接:设置代理超时参数
下一篇
DataWorks