成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

【Go微服務】一文帶你玩轉ProtoBuf

開發 前端
通過這篇文章,我們不僅學會了ProtoBuf的入門操作,還使用Go語言基于ProtoBuf編碼解碼了數據,進行了實戰。進階部分帶大家了解了ProtoBuf如何定義消息、ProtoBuf和Go數據類型的映射、枚舉類型如何使用、通過消息嵌套復用代碼、使用map類型時需要注意的問題和小技巧。

前言

在網絡通信和通用數據交換等應用場景中經常使用的技術是 JSON 或 XML,在微服務架構中通常使用另外一個數據交換的協議的工具ProtoBuf。

ProtoBuf也是我們做微服務開發,進行Go進階實戰中,必知必會的知道點。

今天就開始第一章內容:《一文帶你玩轉ProtoBuf》

5分鐘入門

1.1 簡介

你可能不知道ProtoBuf,但一定知道json或者xml,從一定意義上來說他們的作用是一樣的。

ProtoBuf全稱:protocol buffers,直譯過來是:“協議緩沖區”,是一種與語言無關、與平臺無關的可擴展機制,用于序列化結構化數據。

和json\xml最大的區別是:json\xml都是基于文本格式,ProtoBuf是二進制格式。

ProtoBuf相比于json\XML,更小(3 ~ 10倍)、更快(20 ~ 100倍)、更為簡單。

我們只需要定義一次數據結構,就可以使用ProtoBuf生成源代碼,輕松搞定在各種數據流和各種語言中寫入、讀取結構化數據。

1.2 安裝

建議大家使用主流版本v3,這是官網下載地址:https://github.com/protocolbuffers/ProtoBuf/releases

注意,不同的電腦系統安裝包是不一樣的:

  • Windows 64位 點這里下載
  • Windows 32位 點這里下載
  • Mac Intel 64位 點這里下載
  • Mac ARM 64位 點這里下載
  • Linux 64位 點這里下載

(公眾號無法跳轉到外鏈,點擊文末的閱讀原文可以跳轉到下載地址。)

小技巧:Mac查看自己的芯片類型點擊左上角的蘋果圖標,再點擊關于本機,就可以查看了。

比如,我的處理器芯片是intel的,下載安裝包之后是這樣的:

bin目錄下的protoc是ProtoBuf的工具集,下文會重點介紹它的使用。

注意:我們需要將下載得到的可執行文件protoc所在的 bin 目錄加到我們電腦的環境變量中。

Mac安裝小技巧

如果你的Mac安裝了brew,安裝ProtoBuf就更簡單了,我們使用brew install ProtoBuf就可以了

1.3 編譯go語言的工具包

這個protoc可以將proto文件編譯為任何語言的文件,想要編譯為go語言的,還需要下載另外一個可執行文件

命令是這樣的:

go install google.golang.org/ProtoBuf/cmd/protoc-gen-go@latest

1.4 編寫proto代碼

下面就編寫一個非常簡單,但是五臟齊全的proto代碼,我們再根據這段代碼生成pb.go文件。

syntax = "proto3";

package hello;

option go_package = "./;hello";

message Say{
int64 id = 1;
string hello = 2;
repeated string word = 3;
}

1.5 生成go代碼

生成go代碼,非常簡單,使用下面的命令就可以了。

切換到.proto文件所在目錄

cd proto/demo/

指定proto源文件,自動生成代碼。

protoc --go_out=. hello.proto

執行上面的命令后,我們在項目中就自動生成了一個.pb.go的文件

入門ProtoBuf就是這么的簡單:通過這幾步我們就完成了ProtoBuf的下載、安裝、編寫了一個proto文件,并生成了能用Go語言讀寫ProtoBuf的源代碼。

我們再深入了解一下probuf的用法:

10分鐘進階

下面再帶大家深入了解一下ProtoBuf的知識點,避免在開發中踩坑。

小技巧:寫proto和寫go最大的區別是需要在結尾添加分號的;,在開發過程中給自己提個醒:如果是寫proto需要加分號,如果是寫go不需要加分號。

以我們上面的proto入門代碼舉例:

1.1 關鍵字

  • syntax:是必須寫的,而且要定義在第一行;目前proto3是主流,不寫默認使用proto2
  • package:定義我們proto文件的包名
  • option go_package:定義生成的pb.go的包名,我們通常在proto文件中定義。如果不在proto文件中定義,也可以在使用protoc生成代碼時指定pb.go文件的包名

message:非常重要,用于定義消息結構體,不用著急,下文會重點講解

細心的小伙伴一定注意到了 message 消息體中有一個 “repeated” 關鍵字,這在我們寫Go的時候是沒有的。

這是干什么用的呢?下面來詳細解答一下:

1.2 數組類型

關于數組類型,和Java、Go、PHP等語言中,定義數據類型不一樣。

在ProtoBuf消息中定義數組類型,是通過在字段前面增加repeated關鍵詞實現,標記當前字段是一個數組。

只要使用repeated標記類型定義,就表示數組類型。

我們來舉兩個例子:

(1)整數數組:

下面定義的arrays表示int32類型的數組

message Msg {
repeated int32 arrays = 1;
}

(2)字符串數組

下面定義的names表示字符串數組

message Msg {
repeated string names = 1;
}

repeated搞懂了,message又是干嘛用的呢?

1.3 消息

消息(message),在ProtoBuf中指的就是我們要定義的數據結構。類似于Go中定義結構體。

message關鍵詞用法也非常簡單:

(1) 語法

syntax = "proto3";

message 消息名 {
消息體
}

例子:

syntax = "proto3";

message Request {
string query = 1;
int32 page = 2;
int32 limit = 3;
}

定義了一個Request消息,這個消息有3個字段,query是字符串類型,page和limit是int32類型。

1.4 字段類型

ProtoBuf支持多種數據類型,例如:string、int32、double、float等等,我整理了一份ProtoBuf和go語言的數據類型映射表

.proto Type

Go Type

使用技巧

double

float64

沒特殊技巧,記住float對應go的float32,double對應go的float64就可以了

float

float32

沒特殊技巧,記住float對應go的float32,double對應go的float64就可以了

int32

int32

使用變長編碼,對于負值的效率很低,如果你的域有可能有負值,請使用sint64替代

uint32

uint32

使用變長編碼

uint64

uint64

使用變長編碼

sint32

int32

使用變長編碼,這些編碼在負值時比int32高效的多

sint64

int64

使用變長編碼,有符號的整型值。編碼時比通常的int64高效。

fixed32

uint32

總是4個字節,如果數值都比228大的話,這個類型會比uint32高效。

fixed64

uint64

總是8個字節,如果數值都比256大的話,這個類型會比uint64高效。

sfixed32

int32

總是4個字節

sfixed64

int64

總是8個字節

bool

bool

嚴格對應,玩不出其他花樣來

string

string

一個字符串必須是UTF-8編碼或者7-bit ASCII編碼的文本。

bytes

[]byte

可以包含任意順序的字節數組

1.5 分配標識號

細心的小伙伴可能又有疑問了,上面消息體中的 string query = 1; 這個1是什么呢?

這些數字是“分配表示號”:在消息定義中,每個字段后面都有一個唯一的數字,這個就是標識號。

這些標識號的作用是:用來在消息的二進制格式中識別各個字段的,一旦開始使用就不能夠再改變。

注意:分配標識號在每個消息內唯一,不同的消息體是可以擁有相同的標識號的。

小技巧:[1,15]之內的標識號在編碼的時候會占用一個字節。[16,2047]之內的標識號則占用2個字節。所以應該為那些頻繁出現的消息元素保留 [1,15]之內的標識號。

1.5.1 保留標識號(Reserved)

小技巧:要為將來有可能添加的、頻繁出現的字段預留一些標識號。

我們想保留一些標識號,留給以后用,可以使用下面語法:

message Test {
reserved 2, 5, 7 to 10; // 保留2,5,7到10這些標識號
}

如果使用了這些保留的標識號,protocol buffer編譯器無法編譯通過,將會輸出警告信息。

1.6 將消息編譯成各種語言版本的類庫

編譯器命令格式:

protoc [OPTION] PROTO_FILES

OPTION是命令的選項, PROTO_FILES是我們要編譯的proto消息定義文件,支持多個。

常用的OPTION選項:

--go_out=OUT_DIR            指定代碼生成目錄,生成 Go 代碼
--cpp_out=OUT_DIR 指定代碼生成目錄,生成 C++ 代碼
--csharp_out=OUT_DIR 指定代碼生成目錄,生成 C# 代碼
--java_out=OUT_DIR 指定代碼生成目錄,生成 java 代碼
--js_out=OUT_DIR 指定代碼生成目錄,生成 javascript 代碼
--objc_out=OUT_DIR 指定代碼生成目錄,生成 Objective C 代碼
--php_out=OUT_DIR 指定代碼生成目錄,生成 php 代碼
--python_out=OUT_DIR 指定代碼生成目錄,生成 python 代碼
--ruby_out=OUT_DIR 指定代碼生成目錄,生成 ruby 代碼

因為開篇我們就用Go舉了例子,下面再用Java舉個例子吧:

protoc --java_out=. hello.proto

在當前目錄導出java版本的代碼,編譯hello.proto消息,執行效果如下:

下載再帶小伙伴們了解一下ProtoBuf的進階知識點吧:枚舉類型、消息嵌套和Map類型。

1.7 枚舉類型

寫Java的同學枚舉一定用的很溜,但是寫Go的同學可能有點懵了,Go是不直接支持枚舉的,并沒有Enum關鍵字。

關注我,后續會詳解Go枚舉相關的知識點,在這篇文章中不做重點介紹。

使用枚舉的場景是這樣的:

當定義一個消息類型的時候,可能想為一個字段指定“預定義值”中的其中一個值,這時候我們就可以通過枚舉實現,比如這種:

syntax = "proto3";//指定版本信息,非注釋的第一行

enum SexType //枚舉消息類型,使用enum關鍵詞定義,一個性別類型的枚舉類型
{
UNKONW = 0; //proto3版本中,首成員必須為0,成員不應有相同的值
MALE = 1; //1
FEMALE = 2; //20未知
}

// 定義一個用戶消息
message UserInfo
{
string name = 1; // 姓名字段
SexType sex = 2; // 性別字段,使用SexType枚舉類型
}

運行效果如下:

在實際開發中,我們需要定義很多的proto,我們如何做到消息的復用呢?

答案就是:“消息嵌套”

1.8 消息嵌套

我們在開發Java和PHP時,經常嵌套使用類,也可以使用其他類作為自己的成員屬性類型;在開發Go時經常嵌套使用結構體。

在ProtoBuf中同樣支持消息嵌套,可以在一個消息中嵌套另外一個消息,字段類型可以是另外一個消息類型。

我們來看下面3個經典示例:

1.8.1 引用其他消息類型的用法

// 定義Article消息
message Article {
string url = 1;
string title = 2;
repeated string tags = 3; // 字符串數組類型
}

// 定義ListArticle消息
message ListArticle {
// 引用上面定義的Article消息類型,作為results字段的類型
repeated Article articles = 1; // repeated關鍵詞標記,說明articles字段是一個數組
}

1.8.2 消息嵌套

類似類嵌套一樣,消息也可以嵌套,比如這樣:

message ListArticle {
// 嵌套消息定義
message Article {
string url = 1;
string title = 2;
repeated string tags = 3;
}
// 引用嵌套的消息定義
repeated Article articles = 1;
}

1.8.3 import導入其他proto文件定義的消息

我們在實際開發中,通常要定義很多消息,如果都寫在一個proto文件,是不方便維護的。

小技巧:將消息定義寫在不同的proto文件中,在需要的時候可以通過import導入其他proto文件定義的消息。

例子:

創建文件: article.proto

syntax = "proto3";

package nesting;

option go_package = "./;article";

message Article {
string url = 1;
string title = 2;
repeated string tags = 3; // 字符串數組類型
}

創建文件: list_article.proto

syntax = "proto3";
// 導入Article消息定義
import "article.proto";

package nesting;

option go_package = "./;article";

// 定義ListArticle消息
message ListArticle {
// 使用導入的Result消息
repeated Article articles = 1;
}

執行效果如下,我們順利生成了.pb.go文件:

1.9 map類型

我們在Go語言開發中,最常用的就是切片類型和map類型了。

切片類型在ProtoBuf中對應的就是repeated類型,前面我們已經介紹過了。

再重點介紹一下map類型,ProtoBuf也是支持map類型的:

1.9.1 map語法

map<key_type, value_type> map_field = N;

語法非常簡單和通用,但是有幾個問題需要我們注意:

  • key_type可以是任何整數或字符串類型(除浮點類型和字節之外的任何標量類型)。
  • 注意:枚舉不是有效的key_type。
  • value_type 可以是除另一個映射之外的任何類型。
  • Map 字段不能使用repeated關鍵字修飾。

1.9.2 map的例子

我們舉個典型的例子:學生的學科和分數就適合用map定義:

syntax = "proto3";

package map;

option go_package = "./;score";

message Student{
int64 id = 1; //id
string name = 2; //學生姓名
map<string, int32> score = 3; //學科 分數的map
}

運行效果如下: 

再強調一下:

注意:Map 字段是不能使用repeated關鍵字修飾。

至此我們已經掌握了ProtoBuf的所有知識點,是不是非常簡單清晰呢?

下面我們在Go項目中實戰應用一下ProtoBuf,從ProtoBuf中讀取數據,并且轉換為我們常用的結構體

5分鐘實戰

1. 首先我們定義proto文件

我創建了一個demo目錄,創建了名為study_info.proto的文件

syntax = "proto3";

package demo;

option go_package = "./;study";

message StudyInfo {
int64 id = 1; //id
string name = 2; //學習的科目名稱
int32 duration = 3; //學習的時長 單位秒
map<string, int32> score = 4; //學習的分數
}

2. 生成代碼

使用命令生成pb.go文件:

protoc --go_out=. study_info.proto

3.編寫go文件

編寫go文件,讀取ProtoBuf中定義的字段,進行賦值,取值,轉成結構體等操作:

proto編碼和解碼的操作和json是非常像的,都使用“Marshal”和“Unmarshal”關鍵字。

package main

import (
"fmt"
"google.golang.org/ProtoBuf/proto"
study "juejin/ProtoBuf/proto/demo"
)

func main() {
// 初始化proto中的消息
studyInfo := &study.StudyInfo{}

//常規賦值
studyInfo.Id = 1
studyInfo.Name = "學習ProtoBuf"
studyInfo.Duration = 180

//在go中聲明實例化map賦值給ProtoBuf消息中定義的map
score := make(map[string]int32)
score["實戰"] = 100
studyInfo.Score = score

//用字符串的方式:打印ProtoBuf消息
fmt.Printf("字符串輸出結果:%v\n", studyInfo.String())

//轉成二進制文件
marshal, err := proto.Marshal(studyInfo)
if err != nil {
return
}
fmt.Printf("Marshal轉成二進制結果:%v\n", marshal)

//將二進制文件轉成結構體
newStudyInfo := study.StudyInfo{}
err = proto.Unmarshal(marshal, &newStudyInfo)
if err != nil {
return
}
fmt.Printf("二進制轉成結構體的結果:%v\n", &newStudyInfo)
}

運行結果如下:

本文總結

ProtoBuf作為開發微服務必選的數據交換協議,基于二進制傳輸,比json/xml更小,速度更快,使用也非常的簡單。

通過這篇文章,我們不僅學會了ProtoBuf的入門操作,還使用Go語言基于ProtoBuf編碼解碼了數據,進行了實戰。

進階部分帶大家了解了ProtoBuf如何定義消息、ProtoBuf和Go數據類型的映射、枚舉類型如何使用、通過消息嵌套復用代碼、使用map類型時需要注意的問題和小技巧。

本文轉載自微信公眾號「 程序員升級打怪之旅」,作者「王中陽Go」,可以通過以下二維碼關注。

轉載本文請聯系「 程序員升級打怪之旅」公眾號。

責任編輯:武曉燕 來源: 程序員升級打怪之旅
相關推薦

2022-04-08 09:01:14

CSS自定義屬性前端

2024-06-27 10:50:01

2020-11-17 09:32:57

設計模式責任鏈

2020-05-11 14:35:11

微服務架構代碼

2021-09-27 07:39:52

Go初始化函數package

2022-09-21 16:56:16

設計模式微服務架構

2022-12-20 07:39:46

2023-11-20 08:18:49

Netty服務器

2023-12-21 17:11:21

Containerd管理工具命令行

2023-11-21 08:37:09

2020-10-29 08:55:04

微服務

2023-07-31 08:18:50

Docker參數容器

2023-11-06 08:16:19

APM系統運維

2021-05-29 10:11:00

Kafa數據業務

2022-11-11 19:09:13

架構

2023-10-27 08:15:45

2022-02-24 07:34:10

SSL協議加密

2023-11-08 08:15:48

服務監控Zipkin

2024-03-26 00:17:51

Go語言IO

2019-06-13 21:31:19

AI
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产成人一区 | 欧美另类视频在线 | 狠狠爱综合网 | 欧美日韩福利视频 | 久久久www成人免费精品 | 日韩国产一区二区三区 | 中文字幕中文字幕 | 一区二区日本 | 黄色大片免费网站 | 视频精品一区二区三区 | 久在线 | 请别相信他免费喜剧电影在线观看 | 亚洲第一成人av | 一区二区免费 | 亚洲精品日韩在线观看 | 一二三区在线 | 另类一区 | 国产99久久久国产精品下药 | 亚洲精品一级 | 99这里只有精品 | 九九久久久 | 黑人精品欧美一区二区蜜桃 | 欧美综合一区二区 | 伊人二区| 中文精品视频 | 少妇精品久久久久久久久久 | av网站在线看 | 成人日b视频 | 在线观看视频一区二区三区 | 一级女毛片| 欧美久久视频 | 欧美精品二区 | 精品一区二区免费视频 | 日韩午夜影院 | 一区二区中文字幕 | 老熟女毛片 | 亚洲一区二区三区久久 | 夜夜干夜夜操 | 影音先锋男 | 韩日在线 | 日韩伦理电影免费在线观看 |