Пример
google.golang.org/protobuf v1.32.0: Convert between dynamic Go data structures and Protocol Buffers Struct, ListValue, and Value with structpb
Проверенный пример — golang google.golang.org/protobuf v1.32.0: Convert between dynamic Go data structures and Protocol Buffers Struct, ListValue, and Value…
sha256:5da721c1166d04ed80369d75435c1584df3cd3d121055f0c4872d4ebf8d74090
Эта сеть предлагает одно: образец, который собирается. Она запустила его в песочнице и сохранила подписанную квитанцию. Она ничего не оценивает и ничего не гарантирует — собирается ли тот же код у вас, она не измеряла.
Сколько различных ключей подписи подали пройденную квитанцию контракта. Один — только автор; больше одного — значит, кто-то ещё тоже собрал. Ключ создаётся сам и не имеет зарегистрированной личности, поэтому считаются ключи, а не люди.
MIT-0
Свидетельства выполнения
Заявленное окружение и подписанные запуски разделены, чтобы вы точно видели, что этот образец запускал и где.
- Основа свидетельства
- Подписанный контракт пройден
- Квитанции проверки
- 1
- Ключи подписи, собравшие его
- 1
Заявленная среда
go linux 24 · ubuntu · glibc 2.39 x64 go go go
Среды запусков проверки
| Окружение | Контракт | Этапы | Запуск |
|---|---|---|---|
| go 1.26 · linux alpine/x64 · docker ed25519:c1973797be207ac4 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · golang@1golang:1.26-alpine@sha256:28d89ee9cc0f… |
2026-08-28 |
Кейс
HOW- Цель
- Convert between dynamic Go data structures and Protocol Buffers Struct, ListValue, and Value with structpb
- Символы
-
- google.golang.org/protobuf/types/known/structpb.ListValue.AsSlice
- google.golang.org/protobuf/types/known/structpb.NewList
- google.golang.org/protobuf/types/known/structpb.NewStruct
- google.golang.org/protobuf/types/known/structpb.NewValue
- google.golang.org/protobuf/types/known/structpb.Struct.AsMap
- google.golang.org/protobuf/types/known/structpb.Value.AsInterface
- Окружение
- go
- Создан
- 2026-08-28T09:04:35Z
Контракт
- structpb.NewValue converts Go primitives (nil, bool, int/int32/int64/float32/float64, string) to appropriate Value kinds with numeric types represented as float64 NumberValue.
- structpb.NewStruct converts Go maps into *structpb.Struct, and Struct.AsMap converts it back to map[string]interface{}, while calling AsMap on a nil receiver safely returns an empty non-nil map.
- structpb.NewList converts Go slices into *structpb.ListValue, and ListValue.AsSlice converts it back to []interface{}, while calling AsSlice on a nil receiver safely returns an empty non-nil slice.
- structpb.Value.AsInterface recursively unpacks nested StructValue and ListValue into corresponding Go map and slice representations, and calling AsInterface on a nil receiver safely returns nil.
- structpb.NewValue returns an error when passed unsupported Go types such as channels or functions, and NewStruct/NewList propagate conversion failures for nested unsupported types.
- structpb.Struct supports proto binary wire serialization and protojson serialization formatting as a standard JSON object.
Файлы
- NOTES.md
- PROMPT.md
- csx.json
- go.mod
- go.sum
- spec.json
- structpb_test.go
Исходный код
# Protocol Buffers structpb Dynamic Value Conversion
A search for dynamic Go data structure conversion using `structpb` in `google.golang.org/protobuf@v1.32.0` returned `NO_SAFE_MATCH`.
This sample tests and verifies conversion semantics between dynamic Go types (primitives, maps, slices) and Protocol Buffers `Struct`, `ListValue`, and `Value` messages.
## Observed Behavior
1. **Primitive Value Conversion (`structpb.NewValue`)**:
- `structpb.NewValue(nil)` produces a `*structpb.Value` with `NullValue_NULL_VALUE`. Calling `AsInterface()` on it returns `nil`.
- `structpb.NewValue(bool)` maps to `BoolValue`.
- Integer types (`int`, `int32`, `int64`) and float types (`float32`, `float64`) map to `NumberValue` and are normalized as `float64`.
- String values map to `StringValue`.
2. **Map Conversion (`structpb.NewStruct` & `Struct.AsMap`)**:
- `structpb.NewStruct(map[string]interface{})` converts Go maps to `*structpb.Struct`.
- `st.AsMap()` extracts the values back into a `map[string]interface{}`.
- Calling `AsMap()` on a `nil` receiver safely returns an empty non-nil `map[string]interface{}{}` without panicking.
- `structpb.NewStruct(nil)` succeeds and returns an empty `Struct`.
3. **Slice Conversion (`structpb.NewList` & `ListValue.AsSlice`)**:
- `structpb.NewList([]interface{})` converts Go slices to `*structpb.ListValue`.
- `listVal.AsSlice()` converts the elements back into `[]interface{}`.
- Calling `AsSlice()` on a `nil` receiver safely returns an empty non-nil `[]interface{}{}` without panicking.
- `structpb.NewList(nil)` succeeds and returns an empty `ListValue`.
4. **Recursive Nested Unpacking (`structpb.Value.AsInterface`)**:
- `Value.AsInterface()` recursively unpacks nested structs into Go maps and nested lists into Go slices.
- Calling `AsInterface()` on a `nil` receiver safely returns `nil`.
5. **Error Handling on Unsupported Types**:
- Types that cannot be represented in JSON / protobuf Struct (e.g. channels, functions) return an error from `structpb.NewValue`.
- Nested unsupported types within maps or slices cause `structpb.NewStruct` or `structpb.NewList` to fail with an error.
6. **Serialization & Interoperability**:
- `structpb.Struct` supports both binary protobuf wire serialization (`proto.Marshal` / `proto.Unmarshal`) and JSON serialization (`protojson.Marshal` / `protojson.Unmarshal`), serializing directly as a standard JSON object.
Clean-room public code sample — generation instructions
Write a brand-new, minimal, self-contained code sample in this clean-room directory.
Do not copy, paraphrase, or reference any existing project source. Work only from this spec.
A csx.json manifest scaffold already exists. Do not recreate it from memory. Preserve its case.goal, packages and symbols; fill its empty case.contract with exact assertions and correct its environment, commands and verifierAdapter for the files you generate.
Goal: Convert between dynamic Go data structures and Protocol Buffers Struct, ListValue, and Value with structpb
Kind: HOW
Use EXACTLY these public packages and versions:
- pkg:golang/google.golang.org/protobuf@v1.32.0
Demonstrate these symbols/APIs:
- google.golang.org/protobuf/types/known/structpb.ListValue.AsSlice
- google.golang.org/protobuf/types/known/structpb.NewList
- google.golang.org/protobuf/types/known/structpb.NewStruct
- google.golang.org/protobuf/types/known/structpb.NewValue
- google.golang.org/protobuf/types/known/structpb.Struct.AsMap
- google.golang.org/protobuf/types/known/structpb.Value.AsInterface
Rules:
- One focused purpose; the smallest project that proves the goal.
- Include a contract test (test/contract.*) that runs OFFLINE and exits 0 exactly when the goal behavior works.
- Pin every dependency with a lockfile so resolution is reproducible.
- No secrets, credentials, or tokens. No real URLs (only example.com or localhost). No absolute paths.
- No personal names, emails, company names, or project identifiers of any kind.
- No binaries and no generated output (node_modules, dist, target, venv, .git, .env).
- Keep it under 200 files and 256KB packed.
{"case":{"caseId":"case:sha256:e798699eb41f7a4f3f5388da7cc9e2b3de7df159eb0cc3ffff9b99988cadfe98","contract":["structpb.NewValue converts Go primitives (nil, bool, int/int32/int64/float32/float64, string) to appropriate Value kinds with numeric types represented as float64 NumberValue.","structpb.NewStruct converts Go maps into *structpb.Struct, and Struct.AsMap converts it back to map[string]interface{}, while calling AsMap on a nil receiver safely returns an empty non-nil map.","structpb.NewList converts Go slices into *structpb.ListValue, and ListValue.AsSlice converts it back to []interface{}, while calling AsSlice on a nil receiver safely returns an empty non-nil slice.","structpb.Value.AsInterface recursively unpacks nested StructValue and ListValue into corresponding Go map and slice representations, and calling AsInterface on a nil receiver safely returns nil.","structpb.NewValue returns an error when passed unsupported Go types such as channels or functions, and NewStruct/NewList propagate conversion failures for nested unsupported types.","structpb.Struct supports proto binary wire serialization and protojson serialization formatting as a standard JSON object."],"goal":"Convert between dynamic Go data structures and Protocol Buffers Struct, ListValue, and Value with structpb","kind":"HOW","packages":["pkg:golang/google.golang.org/protobuf@v1.32.0"],"schemaVersion":1,"symbols":["google.golang.org/protobuf/types/known/structpb.ListValue.AsSlice","google.golang.org/protobuf/types/known/structpb.NewList","google.golang.org/protobuf/types/known/structpb.NewStruct","google.golang.org/protobuf/types/known/structpb.NewValue","google.golang.org/protobuf/types/known/structpb.Struct.AsMap","google.golang.org/protobuf/types/known/structpb.Value.AsInterface"]},"contractCommand":["go","test","./..."],"environment":{"arch":"x64","distro":"ubuntu","ecosystem":"golang","executionContext":"go","language":"go","libc":"glibc","libcVersion":"2.39","os":"linux","osVersionBucket":"24","packageManager":"go","runtime":"go","schemaVersion":1},"license":"MIT-0","packages":["pkg:golang/google.golang.org/protobuf@v1.32.0"],"schemaVersion":1,"subject":"pkg:golang/google.golang.org/protobuf@v1.32.0","symbols":["google.golang.org/protobuf/types/known/structpb.ListValue.AsSlice","google.golang.org/protobuf/types/known/structpb.NewList","google.golang.org/protobuf/types/known/structpb.NewStruct","google.golang.org/protobuf/types/known/structpb.NewValue","google.golang.org/protobuf/types/known/structpb.Struct.AsMap","google.golang.org/protobuf/types/known/structpb.Value.AsInterface"],"verifierAdapter":"golang@1"}
module example.com/structpbdemo
go 1.23
require google.golang.org/protobuf v1.36.12
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
{
"schemaVersion": 1,
"goal": "Convert between dynamic Go data structures and Protocol Buffers Struct, ListValue, and Value with structpb",
"kind": "HOW",
"packages": [
"pkg:golang/google.golang.org/protobuf@v1.32.0"
],
"symbols": [
"google.golang.org/protobuf/types/known/structpb.ListValue.AsSlice",
"google.golang.org/protobuf/types/known/structpb.NewList",
"google.golang.org/protobuf/types/known/structpb.NewStruct",
"google.golang.org/protobuf/types/known/structpb.NewValue",
"google.golang.org/protobuf/types/known/structpb.Struct.AsMap",
"google.golang.org/protobuf/types/known/structpb.Value.AsInterface"
]
}
package structpbdemo_test
import (
"reflect"
"testing"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/structpb"
)
// TestStructPBNewValuePrimitives verifies structpb.NewValue conversion from Go primitives,
// ensuring types map to appropriate Value kinds and AsInterface() round-trips accurately.
func TestStructPBNewValuePrimitives(t *testing.T) {
// 1. Nil / NullValue
vNil, err := structpb.NewValue(nil)
if err != nil {
t.Fatalf("NewValue(nil) failed: %v", err)
}
if _, ok := vNil.GetKind().(*structpb.Value_NullValue); !ok {
t.Fatalf("expected NullValue kind, got %T", vNil.GetKind())
}
if got := vNil.AsInterface(); got != nil {
t.Fatalf("expected AsInterface() for nil value to return nil, got %#v", got)
}
// 2. Bool
vBool, err := structpb.NewValue(true)
if err != nil {
t.Fatalf("NewValue(true) failed: %v", err)
}
if got, ok := vBool.GetKind().(*structpb.Value_BoolValue); !ok || !got.BoolValue {
t.Fatalf("expected BoolValue(true), got %v", vBool.GetKind())
}
if got := vBool.AsInterface(); got != true {
t.Fatalf("expected AsInterface() to return true, got %v", got)
}
// 3. Numbers: integers and floats are converted to float64 NumberValue
numbers := []interface{}{
int(42),
int32(100),
int64(9999),
float32(3.14),
float64(2.71828),
}
for _, num := range numbers {
vNum, err := structpb.NewValue(num)
if err != nil {
t.Fatalf("NewValue(%T(%v)) failed: %v", num, num, err)
}
if _, ok := vNum.GetKind().(*structpb.Value_NumberValue); !ok {
t.Fatalf("expected NumberValue kind for %T, got %T", num, vNum.GetKind())
}
if _, ok := vNum.AsInterface().(float64); !ok {
t.Fatalf("expected AsInterface() to return float64 for %T, got %T", num, vNum.AsInterface())
}
}
// 4. String
vStr, err := structpb.NewValue("test-string")
if err != nil {
t.Fatalf("NewValue(string) failed: %v", err)
}
if got, ok := vStr.GetKind().(*structpb.Value_StringValue); !ok || got.StringValue != "test-string" {
t.Fatalf("expected StringValue('test-string'), got %v", vStr.GetKind())
}
if got := vStr.AsInterface(); got != "test-string" {
t.Fatalf("expected AsInterface() to return 'test-string', got %v", got)
}
}
// TestStructPBNewStructAndAsMap verifies structpb.NewStruct converts Go maps into *structpb.Struct
// and Struct.AsMap() converts it back to map[string]interface{}.
func TestStructPBNewStructAndAsMap(t *testing.T) {
inputMap := map[string]interface{}{
"name": "service-config",
"port": float64(8080),
"enabled": true,
"tags": []interface{}{"api", "gateway"},
"extra": nil,
}
st, err := structpb.NewStruct(inputMap)
if err != nil {
t.Fatalf("NewStruct failed: %v", err)
}
if st.Fields == nil {
t.Fatalf("expected non-nil Fields in Struct")
}
// Verify fields
if nameVal := st.Fields["name"].GetStringValue(); nameVal != "service-config" {
t.Errorf("expected name to be 'service-config', got %q", nameVal)
}
if portVal := st.Fields["port"].GetNumberValue(); portVal != 8080 {
t.Errorf("expected port to be 8080, got %v", portVal)
}
if enabledVal := st.Fields["enabled"].GetBoolValue(); !enabledVal {
t.Errorf("expected enabled to be true, got %v", enabledVal)
}
// Convert back via AsMap()
outputMap := st.AsMap()
if !reflect.DeepEqual(inputMap, outputMap) {
t.Fatalf("AsMap() mismatch:\nwant: %#v\ngot: %#v", inputMap, outputMap)
}
// Nil struct safety: calling AsMap() on nil receiver safely returns empty map (not nil)
var nilStruct *structpb.Struct
if got := nilStruct.AsMap(); got == nil || len(got) != 0 {
t.Fatalf("expected nilStruct.AsMap() to return empty non-nil map, got %#v", got)
}
// Empty struct
emptyStruct, err := structpb.NewStruct(nil)
if err != nil {
t.Fatalf("NewStruct(nil) failed: %v", err)
}
if len(emptyStruct.AsMap()) != 0 {
t.Fatalf("expected empty map for NewStruct(nil), got %#v", emptyStruct.AsMap())
}
}
// TestStructPBNewListAndAsSlice verifies structpb.NewList converts Go slices into *structpb.ListValue
// and ListValue.AsSlice() converts it back to []interface{}.
func TestStructPBNewListAndAsSlice(t *testing.T) {
inputSlice := []interface{}{
"first",
float64(42),
false,
map[string]interface{}{"nested_key": "nested_val"},
nil,
}
listVal, err := structpb.NewList(inputSlice)
if err != nil {
t.Fatalf("NewList failed: %v", err)
}
if len(listVal.Values) != len(inputSlice) {
t.Fatalf("expected %d values, got %d", len(inputSlice), len(listVal.Values))
}
outputSlice := listVal.AsSlice()
if !reflect.DeepEqual(inputSlice, outputSlice) {
t.Fatalf("AsSlice() mismatch:\nwant: %#v\ngot: %#v", inputSlice, outputSlice)
}
// Nil list safety: calling AsSlice() on nil receiver safely returns empty slice (not nil)
var nilList *structpb.ListValue
if got := nilList.AsSlice(); got == nil || len(got) != 0 {
t.Fatalf("expected nilList.AsSlice() to return empty non-nil slice, got %#v", got)
}
// Empty list
emptyList, err := structpb.NewList(nil)
if err != nil {
t.Fatalf("NewList(nil) failed: %v", err)
}
if len(emptyList.AsSlice()) != 0 {
t.Fatalf("expected empty slice for NewList(nil), got %#v", emptyList.AsSlice())
}
}
// TestStructPBNestedValueAsInterface verifies nested struct and list value conversions via Value.AsInterface().
func TestStructPBNestedValueAsInterface(t *testing.T) {
nestedData := map[string]interface{}{
"cluster": "us-east-1",
"nodes": []interface{}{
map[string]interface{}{"id": "node-1", "active": true},
map[string]interface{}{"id": "node-2", "active": false},
},
}
val, err := structpb.NewValue(nestedData)
if err != nil {
t.Fatalf("NewValue(nestedData) failed: %v", err)
}
if _, ok := val.GetKind().(*structpb.Value_StructValue); !ok {
t.Fatalf("expected StructValue kind, got %T", val.GetKind())
}
gotInterface := val.AsInterface()
if !reflect.DeepEqual(nestedData, gotInterface) {
t.Fatalf("AsInterface() mismatch on nested data:\nwant: %#v\ngot: %#v", nestedData, gotInterface)
}
// Nil value receiver safety
var nilVal *structpb.Value
if got := nilVal.AsInterface(); got != nil {
t.Fatalf("expected nilVal.AsInterface() to return nil, got %#v", got)
}
}
// TestStructPBUnsupportedTypesError verifies structpb.NewValue returns an error for unsupported Go types (e.g. channels, funcs).
func TestStructPBUnsupportedTypesError(t *testing.T) {
// Channels cannot be converted
ch := make(chan int)
if _, err := structpb.NewValue(ch); err == nil {
t.Fatalf("expected error when calling NewValue on chan, got nil")
}
// Functions cannot be converted
fn := func() {}
if _, err := structpb.NewValue(fn); err == nil {
t.Fatalf("expected error when calling NewValue on func, got nil")
}
// Map with unsupported value returns error in NewStruct
invalidMap := map[string]interface{}{
"bad": ch,
}
if _, err := structpb.NewStruct(invalidMap); err == nil {
t.Fatalf("expected error when calling NewStruct with channel value, got nil")
}
// Slice with unsupported element returns error in NewList
invalidSlice := []interface{}{"ok", fn}
if _, err := structpb.NewList(invalidSlice); err == nil {
t.Fatalf("expected error when calling NewList with func value, got nil")
}
}
// TestStructPBProtoAndJSONSerialization verifies proto wire and JSON serialization of structpb.Struct.
func TestStructPBProtoAndJSONSerialization(t *testing.T) {
data := map[string]interface{}{
"env": "production",
"retries": float64(3),
"verbose": false,
}
st, err := structpb.NewStruct(data)
if err != nil {
t.Fatalf("NewStruct failed: %v", err)
}
// 1. Proto wire serialization
wireBytes, err := proto.Marshal(st)
if err != nil {
t.Fatalf("proto.Marshal failed: %v", err)
}
unmarshaledSt := &structpb.Struct{}
if err := proto.Unmarshal(wireBytes, unmarshaledSt); err != nil {
t.Fatalf("proto.Unmarshal failed: %v", err)
}
if !proto.Equal(st, unmarshaledSt) {
t.Fatalf("proto.Unmarshal result differs from original")
}
// 2. protojson serialization produces canonical JSON representation
jsonBytes, err := protojson.Marshal(st)
if err != nil {
t.Fatalf("protojson.Marshal failed: %v", err)
}
jsonSt := &structpb.Struct{}
if err := protojson.Unmarshal(jsonBytes, jsonSt); err != nil {
t.Fatalf("protojson.Unmarshal failed: %v", err)
}
if !proto.Equal(st, jsonSt) {
t.Fatalf("protojson roundtrip mismatch")
}
}
Исходный сидер
аноним