ข้ามไปยังเนื้อหา

Repeated, Maps & Well-Known

ใส่ 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 เป็น 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)

คุณไม่ต้อง 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"]
well-known type ที่คุณจะได้หยิบมาใช้จริง

ตัวที่คุณจะใช้บ่อยมาก:

  • Timestamp และ Duration — จุดเวลาที่แม่นยำและช่วงเวลา ควรใช้พวกนี้แทน int64 ดิบ ๆ ที่แปลว่า “millisecond ตั้งแต่อะไรสักอย่าง” เสมอ
  • wrapper (Int32Value, StringValue, BoolValue, …) — กล่อง message ที่ห่อ scalar ไว้เพื่อให้ nullable เป็นทางเลือกเก่าก่อนจะมี keyword optional แต่ยังพบบ่อยใน 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 ไหนบ้าง
}
การใส่ `repeated` ที่ field ทำอะไร?
ข้อไหนจริงเกี่ยวกับ map ของ protobuf?
ควร represent จุดเวลาใน message อย่างไร?
`google.protobuf.FieldMask` ใช้ทำอะไร?