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

Scalar Types & Defaults

protobuf มี scalar type มาให้ชุดเล็ก ๆ จุดที่ต้องเลือกให้ดีคือกลุ่ม integer ซึ่งควรเลือกจาก การ encode ไม่ใช่แค่ช่วงค่า

proto typeใช้กับหมายเหตุ
int32 / int64integer ทั่วไปความยาวแปรผัน; ไม่คุ้มกับค่าติดลบ
uint32 / uint64ค่าที่ไม่มีทางติดลบความยาวแปรผัน
sint32 / sint64integer ที่ ติดลบบ่อยZigZag encoding — เล็กกว่ามากสำหรับค่าติดลบ
fixed32 / fixed64ค่าที่มักจะใหญ่4/8 byte คงที่; ชนะ varint เมื่อค่าเกิน ~2^28
float / doubleค่าทศนิยม4 / 8 byte
boolจริง / เท็จ1 byte
stringข้อความ UTF-8ต้องเป็น UTF-8 ที่ถูกต้อง
bytesbinary อะไรก็ได้ลำดับ byte แบบไหนก็ได้

จุดละเอียด: int32/int64 ใช้ encoding แบบ varint ซึ่งกะทัดรัดสำหรับเลขบวกน้อย ๆ แต่เปลือง byte กับค่าติดลบ ถ้า field ติดลบเป็นประจำให้ใช้ sint32/sint64 ถ้าเป็นเลขใหญ่แบบสุ่ม (เช่น hash) fixed64 จะเลี่ยง overhead ของ varint

ใน proto3 ทุก field มี default และ field ที่ไม่เคยถูก set จะแยกไม่ออกจาก field ที่ถูก set เป็นค่า default นั้นพอดี

TypeDefault
ตัวเลข0
boolfalse
string"" (ว่าง)
bytesว่าง
enumvalue แรก (ต้องเป็น 0)
messageไม่ถูก set (คล้าย null)

และนี่คือกับดักที่ทำเอาทุกคนงง

scalar ของ proto3 แบบธรรมดาบอกไม่ได้ว่า “field นี้ถูกส่งมาไหม?” — บอกได้แค่ value และ field ที่หายไปจะอ่านได้เป็น default

flowchart TB
  a["client ไม่ส่ง 'age'"] --> z["server อ่าน age = 0"]
  b["client ส่ง age = 0"] --> z
  z --> q["server แยกไม่ออก
ว่าเกิดกรณีไหน"]
ไม่มี presence ทำให้ absent กับ zero เหมือนกัน

ลองนึกถึง UpdateUser request ที่มี int32 age = 5 ถ้า client อยาก ล้าง age จะส่ง 0 — แต่ client ที่แค่ไม่ยุ่งกับ age ก็ส่ง 0 เหมือนกัน server แยกไม่ออกว่า “set เป็นศูนย์” กับ “ไม่ได้ส่งมา” สำหรับ partial update ความกำกวมนี้คือ bug จริง ๆ

ภายหลัง proto3 นำ field presence กลับมาผ่าน keyword optional scalar ที่เป็น optional จะ track ว่าถูก set ชัด ๆ หรือไม่ ทำให้ generated code มี has_age() / hasAge ให้เช็ก

message UpdateUserRequest {
int64 id = 1;
optional int32 age = 5; // ตอนนี้แยกได้: set กับ unset
}

หยิบ optional มาใช้เมื่อ “ไม่ได้ส่งมา” ต้องต่างจาก “ค่า zero” — เคสคลาสสิกคือ partial update (แบบ PATCH) และ setting ที่ 0/false/"" เป็นค่าที่ user เลือกได้จริง ๆ

type ไหนเหมาะที่สุดกับ integer field ที่ติดลบบ่อย?
ใน proto3 default value ของ string field ที่ไม่ถูก set คืออะไร?
ปัญหา "unset กับ zero" คืออะไร?
ควร mark scalar field เป็น `optional` เมื่อไร?