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

พื้นฐานและ Syntax

Go ถูกออกแบบมาโดยยึดสี่แนวคิดที่ส่งผลต่อทุกสิ่งที่คุณเขียน

ความเรียบง่ายเหนือความฉลาดเกินไป (Simplicity over cleverness) ภาษามี spec เล็ก มี keyword เพียง 25 คำ ตั้งใจไม่มี overloading, ไม่มี default arguments, ไม่มี implicit conversion, และไม่มี inheritance เมื่อคุณอ่าน code ของ Go ที่คนอื่นเขียน มันจะดูเหมือน code ที่คุณเองก็เขียนได้เกือบทุกจุด นั่นคือความตั้งใจ

Compile เร็ว (Fast compile) การ compile เร็วเป็นเป้าหมายการออกแบบตั้งแต่แรก ไม่ใช่สิ่งที่คิดทีหลัง — Go ถูกสร้างขึ้นที่ Google เพื่อแก้ปัญหา build ของ C++ ที่ช้าเป็นนาทีซึ่งผู้สร้างภาษาเจอมาโดยตรง การ compile แม้แต่ codebase ขนาดใหญ่มักใช้เวลาแค่ไม่กี่วินาที ทำให้ loop แก้-compile-รัน สั้นและ iteration เร็ว

Explicit มากกว่า Implicit (Explicit over implicit) การแปลง type และการจัดการ error เป็นแบบ explicit ทั้งหมด ไม่มีอะไรเกิดขึ้นเบื้องหลังที่คุณไม่ได้เขียนเอง ค่าจะอยู่ที่ stack หรือ heap ถูกตัดสินใจโดย escape analysis ของ compiler ไม่ใช่จากสิ่งที่มองเห็นได้ตรงจุดเรียกใช้ — ดูบท Pointers เรื่องนี้ทำให้ code ตามรอยและตรวจสอบได้ง่าย

วิธีเดียวที่ชัดเจน (One obvious way) เครื่องมือของ Go บังคับ code style เดียว (gofmt), module system เดียว (go mod), และ test runner เดียว (go test) การถกเถียงเรื่อง formatting, ลำดับ import, และโครงสร้าง project จึงไม่เกิดขึ้นเลย

// The compiler rejects unused imports and unused local variables.
// This keeps every file minimal and every dependency intentional.
import "fmt"
func greet(name string) string {
return "Hello, " + name
}

go build compile program ของคุณตรงไปเป็น native machine-code binary สำหรับ GOOS/GOARCH ของคุณ — ไม่มี bytecode และไม่มี virtual machine เข้ามาเกี่ยวข้องตอน runtime เลย ต่างจาก Java หรือ CPython interpreter บนเครื่องนี้ go build โปรแกรม “hello world” ไฟล์เดียวจะได้ executable แบบ self-contained ขนาดสองสามเมกะไบต์ (ส่วนใหญ่คือ Go runtime — scheduler กับ garbage collector — ที่ link เข้าไปใน binary โดยตรง) และรันมันต้องการแค่ operating system เท่านั้น: ไม่ต้องติดตั้ง Go ไม่ต้อง ship runtime แยกไปด้วย

go run เป็นแค่ตัวห่อความสะดวก ไม่ใช่ execution model คนละแบบ: มัน compile เป็น binary ชั่วคราวเบื้องหลังแล้วรันทันที จากนั้นทิ้ง binary นั้นไป มันเป็นวิธีเร็วที่สุดสำหรับลองอะไรตอนเรียนรู้ — playground ทุกตัวในเว็บนี้ทำงานแบบ go run — แต่สำหรับอะไรที่คุณ deploy หรือ benchmark ซ้ำ ๆ ให้ go build ครั้งเดียวแล้วรัน binary ที่ได้โดยตรง

บทเรียนหัวข้อ
Variables และ Typesvar, :=, zero values, const, iota, overflow, string ในฐานะ byte
Control Flowif พร้อม init, for (สามรูปแบบ), labeled break/continue, switch
Functionsmultiple return, defer, closure, first-class function, pass-by-value
Packages และ Importspackage, import, ลำดับ initialization, internal/, go.mod

เมื่อจบโมดูลนี้คุณจะอ่านและเขียน idiomatic Go program แบบสมบูรณ์ตั้งแต่ต้นได้

ด้านล่างคือโปรแกรม Go ที่แสดงให้เห็น syntax พื้นฐาน: การประกาศตัวแปรด้วย :=, types หลายชนิด, และการ print ผลลัพธ์

package main
import "fmt"
func main() {
name := "Go"
version := 1.27
fast := true
fmt.Println("Hello from", name)
fmt.Println("Version:", version)
fmt.Println("Fast compile:", fast)
}

รันด้านล่างเพื่อดู output ทุก concept ที่ใช้ที่นี่จะอธิบายอย่างละเอียดในบทเรียนต่อไป:

package main
import "fmt"
func main() {
name := "Go"
version := 1.27
fast := true
fmt.Println("Hello from", name)
fmt.Println("Version:", version)
fmt.Println("Fast compile:", fast)
// Integer arithmetic is exact; no implicit float promotion
a := 10
b := 3
fmt.Println("10 / 3 =", a/b)
fmt.Println("10 % 3 =", a%b)
}
สิ่งที่ได้ประโยชน์ต้นทุน
static typingcompiler จับ bug ก่อน runtimeเขียน code มากกว่า dynamic language เล็กน้อย
keyword เพียง 25 คำเรียนรู้เร็ว, อ่าน code คนอื่นได้ง่ายfeature บางอย่าง (เช่น generics ยุคแรก) ต้องใช้ workaround
fast compilefeedback loop สั้น, iteration เร็วไม่มี REPL ที่สมบูรณ์แบบ
garbage collectionไม่ต้องจัดการ memory เองGC pause ที่ unpredictable ใน latency-critical system
native binary ไม่มี VMไม่ต้องติดตั้ง runtime, startup เร็ว, deploy ง่าย (ไฟล์เดียว)binary ใหญ่กว่า interpreted script; Go runtime ถูก link เข้าไปเสมอ
  • “Go คือ C เวอร์ชันใหม่” — Go มี GC, goroutine, interface, และ module system ที่แตกต่างจาก C โดยสิ้นเชิง
  • “Go ไม่มี OOP” — Go มี struct, method, และ interface ที่ทำ composition ได้ แต่ไม่มี class hierarchy แบบ Java
  • “Go ใช้ได้แค่ backend server” — Go ใช้งานได้กับ CLI tools, DevOps tooling, WebAssembly, embedded systems, และ data pipelines
  • “go run คือวิธีที่ Go program ควรถูกรันใน production” — go run เป็นแค่ความสะดวกตอนพัฒนาที่ compile เป็น binary ทิ้งขว้างทุกครั้ง; Go program ที่ deploy จริงจะ build ครั้งเดียวด้วย go build แล้ว ship binary ตัวนั้นออกไป

ตลอดทุกบทในโมดูลนี้ การตรวจไม่กี่ข้อเดียวกันนี้จับ bug ของ generated code ได้ส่วนใหญ่ก่อนที่มันจะถูกใช้จริง:

  • := ใน if/for ใช้ชื่อ (มักเป็น err) ที่มีอยู่แล้วใน scope ภายนอกซ้ำ หรือแอบประกาศตัวแปรใหม่ที่ shadow มันอยู่?
  • break อยู่ใน switch (หรือ select) ที่ตัวมันเองอยู่ใน for หรือเปล่า? มันออกจากแค่ construct ข้างในเท่านั้น ไม่เคยออกจาก loop
  • defer อยู่ใน loop หรือเปล่า หรือ defer f.Close() ทิ้ง error ที่สำคัญไปหรือเปล่า?
  • function value หรือ struct field ที่เก็บมันอยู่ ถูกเรียกโดยไม่เช็ก nil ก่อนหรือเปล่า?

🐛 หา bug ในโค้ดนี้

type Config struct {
OnReady func()
}
func main() {
c := Config{}
c.OnReady()
}
เฉลย

OnReady เป็น field ชนิด function ที่ไม่เคยถูก assign ค่า จึงมี zero value เป็น nil การเรียก function value ที่เป็น nil จะ panic: runtime error: invalid memory address or nil pointer dereference นี่คือ bug ประเภทเดียวกับ nil pointer dereference — วิธีแก้คือเช็ก if c.OnReady != nil { c.OnReady() } ก่อนเรียก หรือให้ Config มี constructor ที่กำหนด default เป็น no-op function เสมอ

Go บังคับอะไรที่ compile time เพื่อให้ code กระชับ?
อะไรคือ entry point ของทุก executable Go program?
การบังคับ style เดียวของ Go (gofmt) หมายความว่าอะไรในทางปฏิบัติ?
go build ผลิตอะไรออกมาสำหรับ Go program ธรรมดา?
โค้ดนี้ compile ผ่านไหม?
var a int = 3
var b float64 = 1.5
fmt.Println(a + b)
โค้ดนี้จะเกิดอะไรขึ้นตอนรัน?
type Config struct {
    OnReady func()
}

func main() {
    c := Config{}
    c.OnReady()
}