johnpoint

johnpoint

(。・∀・)ノ゙嗨
github

proto 通過字段名獲取值

很久沒有更新博客了,一方面是出去實習比在學校的時候忙,真的很多東西等著我去學,太可怕了,另一方面就是懶

protobuf 真是個好東西,就是在你不知道具體結構的時候想要拿到特定字段的值有點小麻煩,好不容易折騰出來了,寫篇博客記錄一下

func FindByName(name string, msg protoreflect.Message) (has bool, value protoreflect.Value, isList bool) {
	if name == "" {
		return false, *new(protoreflect.Value), false
	}
	msgDesc := msg.Descriptor()
	for i := 0; i < msgDesc.Fields().Len(); i++ {
		if msgDesc.Fields().Get(i).Kind() == protoreflect.MessageKind {
			sonMsg := msgDesc.Fields().Get(i)
			has, value, isList = FindByName(name, msg.Get(sonMsg).Message()) // type mismatch: cannot convert list to message
			if has {
				return has, value, isList
			}
		}
		if msgDesc.Fields().Get(i).Name() == protoreflect.Name(name) {
			return true, msg.Get(msgDesc.Fields().Get(i)), msgDesc.Fields().Get(i).IsList()
		}
	}
	return false, value, false
}

這個還考慮到了在 proto message 裡面嵌套了 message 的一種寫法,僅供參考

update:

有點小坑,如果字段裡面是個切片的話從源碼那邊看,使用 Interface () 函數獲得的 interface 是這個切片的指針,通過反射拿到的類型是 Ptr,導致後續的處理變得有點麻煩,所以我直接在函數內部加了一手判斷,直接判斷是否為 List 類型,返回回來根據布爾值進行相應的處理。

func (v Value) Interface() interface{} {
	switch v.typ {
	case nilType:
		return nil
	case boolType:
		return v.Bool()
	case int32Type:
		return int32(v.Int())
	case int64Type:
		return int64(v.Int())
	case uint32Type:
		return uint32(v.Uint())
	case uint64Type:
		return uint64(v.Uint())
	case float32Type:
		return float32(v.Float())
	case float64Type:
		return float64(v.Float())
	case stringType:
		return v.String()
	case bytesType:
		return v.Bytes()
	case enumType:
		return v.Enum()
	default:
		return v.getIface()
	}
}

func (v Value) getIface() (x interface{}) {
	*(*ifaceHeader)(unsafe.Pointer(&x)) = ifaceHeader{Type: v.typ, Data: v.ptr}
	return x
}
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。