Control Flow
if — พร้อม Init Statement
หัวข้อที่มีชื่อว่า “if — พร้อม Init Statement”if statement ใน Go คล้ายกับภาษาอื่น แต่มีความสามารถพิเศษ: สามารถมี init statement ก่อน condition ได้ ตัวแปรที่ประกาศใน init statement มี scope แค่ภายใน if block นั้น:
// รูปแบบปกติif x > 10 { fmt.Println("big")}
// พร้อม init statement — err มี scope แค่ใน if/else blockif err := doSomething(); err != nil { fmt.Println("error:", err)}Pattern นี้ใช้บ่อยมากกับ error handling ใน Go เพราะ scope ของ err ถูกจำกัดให้แคบที่สุด
for — Loop Keyword เดียวของ Go
หัวข้อที่มีชื่อว่า “for — Loop Keyword เดียวของ Go”Go มี loop keyword เดียวคือ for ซึ่งรองรับสามรูปแบบ:
รูปแบบที่ 1: C-style (init; condition; post)
for i := 0; i < 5; i++ { fmt.Println(i)}รูปแบบที่ 2: Condition-only (เทียบเท่า while)
n := 1for n < 100 { n *= 2}รูปแบบที่ 3: Infinite loop
for { // ออกด้วย break หรือ return if done { break }}for range
หัวข้อที่มีชื่อว่า “for range”for range ใช้สำหรับ iterate ผ่าน collections:
// range over slice: ได้ index และ valuenums := []int{10, 20, 30}for i, v := range nums { fmt.Println(i, v)}
// ต้องการเฉพาะ value: ใช้ _ สำหรับ indexfor _, v := range nums { fmt.Println(v)}
// range over string: ได้ rune (Unicode code point) ไม่ใช่ bytefor i, r := range "Go!" { fmt.Printf("%d: %c\n", i, r)}range ยังใช้กับ map (key, value) และ channel (value จนกว่าปิด) ได้ด้วย
switch ใน Go ไม่มี automatic fallthrough ต่างจาก C/Java ทุก case หยุดโดยอัตโนมัติ ถ้าต้องการ fallthrough ต้องระบุ fallthrough keyword อย่างชัดเจน:
day := "Monday"switch day {case "Saturday", "Sunday": // หลาย value ในหนึ่ง case ได้ fmt.Println("weekend")case "Monday": fmt.Println("start of week")default: fmt.Println("weekday")}Switch-true pattern ใช้แทน if-else chain ที่ซับซ้อน:
switch {case score >= 90: fmt.Println("A")case score >= 80: fmt.Println("B")case score >= 70: fmt.Println("C")default: fmt.Println("F")}เมื่อ switch ไม่มี expression (switch บน true) แต่ละ case เป็น boolean expression ที่ evaluate ตามลำดับ
package main
import "fmt"
func classify(n int) string { switch { case n < 0: return "negative" case n == 0: return "zero" case n < 10: return "small" default: return "large" }}
func main() { // C-style for loop fmt.Println("-- C-style loop --") for i := 1; i <= 3; i++ { fmt.Println(i) }
// Condition-only loop (while equivalent) fmt.Println("-- condition-only loop --") n := 1 for n < 10 { n *= 2 } fmt.Println("n =", n)
// for range over slice fmt.Println("-- range over slice --") fruits := []string{"apple", "banana", "cherry"} for i, v := range fruits { fmt.Println(i, v) }
// switch fmt.Println("-- switch classify --") for _, val := range []int{-5, 0, 7, 42} { fmt.Println(val, "->", classify(val)) }
// if with init statement fmt.Println("-- if with init --") if x := 16; x%2 == 0 { fmt.Println(x, "is even") } else { fmt.Println(x, "is odd") }}Loading Go runtime (first run only, ~8 MB)…
ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| สิ่งที่ได้ | ประโยชน์ | ต้นทุน |
|---|---|---|
for keyword เดียว | เรียนรู้น้อยกว่า, code สม่ำเสมอ | ต้องจำรูปแบบสามแบบ (C-style, condition-only, infinite) |
for range | อ่านง่าย ไม่ต้องจัดการ index เอง | range copy value — mutation ใน loop body ไม่กระทบ original slice |
switch ไม่มี fallthrough อัตโนมัติ | ลด bug จาก forgotten break | ต้องเขียน fallthrough ชัดเจนถ้าต้องการ (rare) |
| if init statement | scope ของ err แคบที่สุด | syntax แปลกสำหรับ developer ที่มาจากภาษาอื่น |
ความเข้าใจผิดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ความเข้าใจผิดที่พบบ่อย”- “
deferช้า” —deferมี overhead น้อยมาก (nanosecond range) ใช้ได้สบายใน production code สำหรับ cleanup - “
rangecopy ทั้ง slice” — range copy เฉพาะ value ของแต่ละ element เท่านั้น ไม่ copy ทั้ง slice และ slice header ก็ถูก evaluate แค่ครั้งเดียวตอนเริ่ม loop - “Go
forloop ต้องใช้ semicolon เหมือน C” —for i := 0; i < n; i++ใช้ semicolon แต่for rangeและ condition-only loop ไม่ต้องใช้
💡 ตัวอย่างจากของจริง
Prometheus ใช้
for rangeใน metric collection loop — iterate ผ่าน target หลายพัน target อย่างมีประสิทธิภาพDocker ใช้
deferในการปิด file handle และ release lock เพื่อป้องกัน resource leak ใน container lifecycle management