Repeated, Maps & Well-Known
repeated field คือ list
หัวข้อที่มีชื่อว่า “repeated field คือ list”ใส่ repeated เข้าไปที่ field แล้ว field นั้นจะกลายเป็น list ที่มีลำดับของ type นั้น — มีค่าได้ตั้งแต่ศูนย์ตัวขึ้นไป
message Playlist { string name = 1; repeated string songs = 2; // string 0..N ตัว repeated Track tracks = 3; // message 0..N ตัว}repeated field รักษาลำดับไว้ และ list ว่างก็คือ default — คุณไม่เคยส่ง “null กับ empty” แยกกัน ทั้งสองอย่างคือสิ่งเดียวกัน สำหรับ list ของ numeric scalar protobuf ใช้ packed encoding เป็น default ใน proto3 คือเก็บค่าติดกันโดยไม่มี tag ต่อ element ทำให้ array ตัวเลขขนาดใหญ่กะทัดรัด
map คือคู่ key/value
หัวข้อที่มีชื่อว่า “map คือคู่ key/value”map เป็น syntactic sugar ของ repeated entry แบบ key/value ให้ container แบบ associative
message Config { map<string, string> labels = 1; map<int64, User> user_by_id = 2;}key เป็น integer, bool หรือ string type ก็ได้ ส่วน value เป็น type อะไรก็ได้ยกเว้น map อีกตัว มีสองข้อควรรู้: ลำดับของ map ไม่ ถูกรับประกันบน wire และ map เป็น repeated ไม่ได้ (ถ้าต้องการ list ของ map ให้ห่อไว้ใน message)
well-known type: standard library ของ protobuf
หัวข้อที่มีชื่อว่า “well-known type: standard library ของ protobuf”คุณไม่ต้อง model เวลา, duration หรือ “value อะไรก็ได้” ขึ้นมาเอง package google.protobuf มี well-known type มาให้ — import แล้วใช้ได้เลย
flowchart LR time["Timestamp / Duration → จุดเวลา & ช่วงเวลา"] wrap["Int32Value, StringValue… → scalar ที่ nullable"] any["Any / Struct → shape แบบ dynamic / ไม่รู้"] util["Empty / FieldMask → call ไม่มี arg & partial update"]
ตัวที่คุณจะใช้บ่อยมาก:
TimestampและDuration— จุดเวลาที่แม่นยำและช่วงเวลา ควรใช้พวกนี้แทนint64ดิบ ๆ ที่แปลว่า “millisecond ตั้งแต่อะไรสักอย่าง” เสมอ- wrapper (
Int32Value,StringValue,BoolValue, …) — กล่อง message ที่ห่อ scalar ไว้เพื่อให้ nullable เป็นทางเลือกเก่าก่อนจะมี keywordoptionalแต่ยังพบบ่อยใน API ที่มีอยู่ Any— บรรจุ message ที่ serialize แล้วแบบอะไรก็ได้พร้อม type URL ของตัวเอง สำหรับ payload ที่ dynamic จริง ๆ ทรงพลังแต่ทำลาย static typing ใช้อย่างประหยัดStruct— ข้อมูลคล้าย JSON แบบอิสระ (object, list, value) เมื่อ shape ไม่รู้ล่วงหน้าจริง ๆEmpty— message ที่ไม่มี field สำหรับ RPC ที่ไม่รับหรือไม่คืนอะไรFieldMask— list ของ field path เป็นวิธีมาตรฐานในการบอกว่า “update เฉพาะ field เหล่านี้” ใน API แบบ partial update
import "google/protobuf/timestamp.proto";import "google/protobuf/field_mask.proto";
message Event { string name = 1; google.protobuf.Timestamp created_at = 2;}
message UpdateUserRequest { User user = 1; google.protobuf.FieldMask update_mask = 2; // จะเปลี่ยน field ไหนบ้าง}