Golang 使用 ProtoBuf Any类型的教程

简介:这篇教程介绍了如何在 Golang 中通过 Protobuf 的 Any 类型打包和解包不同类型的消息,并进行类型断言处理。

教程:

package main

import (
    "fmt"
    "github.com/golang/protobuf/proto"
    "github.com/golang/protobuf/ptypes/any"
    protoreflect "google.golang.org/protobuf/reflect/protoreflect"
    "google.golang.org/protobuf/reflect/protoregistry"
    "log"
    "strings"
)

func main() {
    // 创建 MessageA 对象
    messageA := &MessageA{
        Message: "Hello, World!",
    }

    // 将 MessageA 对象打包到 google.protobuf.Any 中
    anyA, err := proto.Marshal(messageA)
    if err != nil {
        log.Fatal(err)
    }

    // 创建 MessageB 对象
    messageB := &MessageB{
        Value: 42,
    }

    // 将 MessageB 对象打包到 google.protobuf.Any 中
    anyB, err := proto.Marshal(messageB)
    if err != nil {
        log.Fatal(err)
    }

    // 创建包含 Any 类型的列表
    anyList := []*any.Any{
        {
            TypeUrl: "type.googleapis.com/MessageA",
            Value:   anyA,
        },
        {
            TypeUrl: "type.googleapis.com/MessageB",
            Value:   anyB,
        },
    }

    // 遍历 Any 类型列表
    for _, any := range anyList {
        // 解析 Any 对象
        message, err := getMessageTypeFromTypeURL(any.GetTypeUrl())
        if err != nil {
            log.Println(err)
            continue
        }
        err = proto.Unmarshal(any.Value, message.Interface().(proto.Message))
        if err != nil {
            log.Println(err)
            continue
        }

        // 处理解析后的消息对象
        switch msg := message.Interface().(type) {
        case *MessageA:
            fmt.Println("MessageA:", msg.Message)
        case *MessageB:
            fmt.Println("MessageB:", msg.Value)
        default:
            log.Println("Unknown message type")
        }
    }
}

func getMessageTypeFromTypeURL(typeURL string) (protoreflect.Message, error) {
    // 解析 typeURL
    typeName := "grpc.test." + typeURL[strings.LastIndex(typeURL, "/")+1:]

    // 获取类型
    messageType, err := protoregistry.GlobalTypes.FindMessageByName(protoreflect.FullName(typeName))
    if err != nil {
        return nil, fmt.Errorf("Type %s not found", typeName)
    }
    return messageType.New(), nil
}

代码说明:

  1. 创建了 MessageA 和 MessageB 对象,并将这两个对象序列化并打包到 google.protobuf.Any 对象中。
  2. 创建包含 Any 类型的列表anyList。指定了 Any 对象的 TypeUrl,并赋值了之前序列化的 MessageA 和 MessageB 对象。
  3. 遍历 Any 类型列表anyList,解析每个 Any 对象,并进行类型断言处理。我们根据解析的 message 对象,断言其是 MessageA 或者是 MessageB,从而不同类型的处理方式。

函数 getMessageTypeFromTypeURL 中,首先解析TypeUrl获取typeName,然后在全局类型注册表中通过typeName查找对应的反射类型,并生成消息对象实例。

注意:MessageA和MessageB需提前定义,并通过protoc生成对应的Go代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ᖇꫀᧁᖇꫀᧁ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值