# Go: พื้นฐานสำหรับนักพัฒนา Java/Python ในปี 2026 > เรียนรู้ Go อย่างรวดเร็วโดยใช้ประสบการณ์จาก Java หรือ Python Goroutine, channel, interface และ pattern สำคัญสำหรับการเปลี่ยนผ่านอย่างราบรื่น - Published: 2026-01-19 - Updated: 2026-04-10 - Author: SharpSkill - Tags: go, golang, concurrency, goroutines, backend - Reading time: 12 min --- Go (หรือ Golang) ได้สถาปนาตนเองเป็นภาษาที่เลือกใช้สำหรับ microservice, เครื่องมือ CLI และระบบแบบกระจาย สร้างโดย Google ในปี 2009 ผสมผสานความเรียบง่ายของ Python เข้ากับประสิทธิภาพระดับ C สำหรับนักพัฒนาที่มาจาก Java หรือ Python การเปลี่ยนมาใช้ Go นั้นราบรื่นอย่างน่าประหลาดใจเมื่อแนวคิดหลักเข้าที่แล้ว > **ทำไมต้อง Go ในปี 2026?** > > Go เป็นรากฐานของ Docker, Kubernetes, Terraform และโครงสร้างพื้นฐานคลาวด์จำนวนมาก การคอมไพล์ที่รวดเร็ว รองรับ concurrency แบบ native และการ deploy เป็นไฟล์ binary เดียว ทำให้ Go เหมาะสำหรับการพัฒนา backend สมัยใหม่ ## การติดตั้งและตั้งค่า Go การติดตั้ง Go ทำได้ง่ายและสม่ำเสมอบนทุกแพลตฟอร์ม เครื่องมือ `go` จัดการการคอมไพล์ dependency และการทดสอบ ```bash # install.sh # Installation on macOS with Homebrew brew install go # Installation on Linux (Ubuntu/Debian) sudo apt update && sudo apt install golang-go # Verify installation go version # go version go1.22.0 linux/amd64 ``` โครงสร้างโปรเจกต์ Go เป็นไปตามข้อตกลงที่เข้มงวดแต่เรียบง่าย ไฟล์ `go.mod` กำหนดโมดูลและ dependency ต่าง ๆ ```bash # project-setup.sh # Create a new project mkdir my-project && cd my-project go mod init github.com/user/my-project # Generated structure: # my-project/ # ├── go.mod # Module manifest # └── main.go # Entry point # Essential commands go build # Compile the project go run main.go # Compile and execute go test ./... # Run all tests go fmt ./... # Format code automatically ``` ## โปรแกรม Go แรก ต่อไปนี้เป็นโปรแกรมง่าย ๆ ที่แสดง syntax พื้นฐานของ Go การเปรียบเทียบกับ Java และ Python ช่วยให้เห็นความแตกต่างได้ชัดเจน ```go // main.go package main import "fmt" // Program entry point func main() { // Declaration with type inference message := "Hello, Go!" fmt.Println(message) // Explicit declaration var count int = 42 fmt.Printf("Count: %d\n", count) } ``` สิ่งที่สังเกตได้ทันที: ไม่มีเครื่องหมายอัฒภาค ไม่มีวงเล็บรอบเงื่อนไข และการอนุมานประเภทด้วย `:=` Go ให้ความสำคัญกับความกระชับโดยไม่เสียสละความอ่านง่าย ## ตัวแปรและประเภทข้อมูลพื้นฐาน Go เป็นภาษา statically typed แต่มีการอนุมานประเภทที่ยอดเยี่ยม ประเภทพื้นฐานครอบคลุมกรณีใช้งานส่วนใหญ่ ```go // types.go package main import "fmt" func main() { // Short declaration (inside functions only) name := "Alice" // string age := 30 // int height := 1.75 // float64 active := true // bool // Explicit declaration var score int = 100 var rate float64 = 3.14 // Multiple declaration var ( firstName string = "Bob" lastName string = "Smith" points int = 0 ) // Zero values (default values) var count int // 0 var text string // "" (empty string) var flag bool // false var ptr *int // nil fmt.Println(name, age, height, active) } ``` > **ค่า Zero ใน Go** > > ต่างจาก Java หรือ Python ตรงที่ Go จะกำหนดค่าเริ่มต้นให้ตัวแปรเป็น "zero value" โดยอัตโนมัติ: 0 สำหรับตัวเลข, "" สำหรับ string, false สำหรับ bool, nil สำหรับ pointer และ slice ## ฟังก์ชันและการคืนค่าหลายค่า Go อนุญาตให้คืนค่าหลายค่าได้ ซึ่งเป็นคุณสมบัติที่ใช้อย่างกว้างขวางในการจัดการข้อผิดพลาด ```go // functions.go package main import ( "errors" "fmt" ) // Simple function with typed parameters func add(a, b int) int { return a + b } // Multiple returns (idiomatic pattern for errors) func divide(a, b float64) (float64, error) { if b == 0 { return 0, errors.New("division by zero") } return a / b, nil } // Named returns func getUser(id int) (name string, age int, err error) { if id <= 0 { err = errors.New("invalid ID") return } name = "Alice" age = 30 return } // Variadic function func sum(numbers ...int) int { total := 0 for _, n := range numbers { total += n } return total } func main() { // Simple call result := add(5, 3) fmt.Println("5 + 3 =", result) // Explicit error handling quotient, err := divide(10, 3) if err != nil { fmt.Println("Error:", err) return } fmt.Printf("10 / 3 = %.2f\n", quotient) // Ignore a returned value with _ name, _, _ := getUser(1) fmt.Println("User:", name) // Variadic call total := sum(1, 2, 3, 4, 5) fmt.Println("Sum:", total) } ``` ## Struct และ method Struct เป็นส่วนประกอบพื้นฐานสำหรับสร้างประเภทข้อมูลที่กำหนดเองใน Go Method ผูกกับประเภทผ่าน receiver ```go // structs.go package main import "fmt" // Struct definition type User struct { ID int Username string Email string Active bool } // Constructor (convention: NewTypeName) func NewUser(id int, username, email string) *User { return &User{ ID: id, Username: username, Email: email, Active: true, } } // Method with value receiver (copy) func (u User) FullInfo() string { status := "inactive" if u.Active { status = "active" } return fmt.Sprintf("%s <%s> (%s)", u.Username, u.Email, status) } // Method with pointer receiver (modification possible) func (u *User) Deactivate() { u.Active = false } // Method with pointer receiver for modification func (u *User) UpdateEmail(newEmail string) { u.Email = newEmail } func main() { // Create with constructor user := NewUser(1, "alice", "alice@example.com") fmt.Println(user.FullInfo()) // Modify via method user.Deactivate() fmt.Println(user.FullInfo()) // Direct creation user2 := User{ ID: 2, Username: "bob", Email: "bob@example.com", } fmt.Println(user2.FullInfo()) } ``` > **Value vs Pointer Receiver** > > ใช้ pointer receiver (`*User`) เมื่อ method เปลี่ยนแปลงสถานะหรือเมื่อ struct มีขนาดใหญ่ ใช้ value receiver (`User`) สำหรับ method อ่านอย่างเดียวบน struct ที่เบา ## Interface: polymorphism แบบ implicit Interface ใน Go ถูก implement แบบ implicit ประเภทหนึ่งจะเป็นไปตาม interface ถ้า implement method ทั้งหมดของมัน โดยไม่ต้องประกาศอย่างชัดเจน ```go // interfaces.go package main import ( "fmt" "math" ) // Interface definition type Shape interface { Area() float64 Perimeter() float64 } // Rectangle implements Shape implicitly type Rectangle struct { Width, Height float64 } func (r Rectangle) Area() float64 { return r.Width * r.Height } func (r Rectangle) Perimeter() float64 { return 2 * (r.Width + r.Height) } // Circle also implements Shape type Circle struct { Radius float64 } func (c Circle) Area() float64 { return math.Pi * c.Radius * c.Radius } func (c Circle) Perimeter() float64 { return 2 * math.Pi * c.Radius } // Function accepting the interface func PrintShapeInfo(s Shape) { fmt.Printf("Area: %.2f, Perimeter: %.2f\n", s.Area(), s.Perimeter()) } func main() { rect := Rectangle{Width: 10, Height: 5} circle := Circle{Radius: 7} // Polymorphism via interface PrintShapeInfo(rect) PrintShapeInfo(circle) // Slice of interfaces shapes := []Shape{rect, circle} for _, shape := range shapes { PrintShapeInfo(shape) } } ``` แนวทางนี้แตกต่างอย่างสิ้นเชิงจาก Java ที่ `implements` เป็นสิ่งจำเป็น ใน Go การสอดคล้องเป็นแบบโครงสร้าง ไม่ใช่แบบชื่อ ## Slice และ map: คอลเลกชันแบบไดนามิก Slice เป็นมุมมองแบบไดนามิกบน array และ map เป็น hash table ในตัว ```go // collections.go package main import "fmt" func main() { // Slice: dynamic array numbers := []int{1, 2, 3, 4, 5} // Append elements numbers = append(numbers, 6, 7) // Slicing (similar to Python) subset := numbers[1:4] // [2, 3, 4] fmt.Println("Subset:", subset) // Create slice with make scores := make([]int, 0, 10) // len=0, cap=10 scores = append(scores, 100, 95, 88) // Iteration with range for index, value := range numbers { fmt.Printf("numbers[%d] = %d\n", index, value) } // Map: hash table users := map[string]int{ "alice": 30, "bob": 25, } // Add/Update users["charlie"] = 35 // Check existence age, exists := users["alice"] if exists { fmt.Println("Alice's age:", age) } // Delete delete(users, "bob") // Map iteration for name, age := range users { fmt.Printf("%s is %d years old\n", name, age) } } ``` ## การจัดการข้อผิดพลาดแบบ idiomatic Go ไม่มี exception ข้อผิดพลาดเป็นค่าที่คืนกลับอย่างชัดเจน บังคับให้จัดการอย่างเข้มงวด ```go // errors.go package main import ( "errors" "fmt" "os" ) // Sentinel error (for comparison) var ErrNotFound = errors.New("resource not found") var ErrInvalidInput = errors.New("invalid input") // Custom error with context type ValidationError struct { Field string Message string } func (e *ValidationError) Error() string { return fmt.Sprintf("validation failed on %s: %s", e.Field, e.Message) } // Function returning different error types func GetUser(id int) (string, error) { if id <= 0 { return "", &ValidationError{ Field: "id", Message: "must be positive", } } if id > 1000 { return "", ErrNotFound } return "Alice", nil } // Error wrapping (Go 1.13+) func ReadConfig(path string) ([]byte, error) { data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("reading config %s: %w", path, err) } return data, nil } func main() { // Basic pattern user, err := GetUser(-1) if err != nil { fmt.Println("Error:", err) // Type assertion for custom error var valErr *ValidationError if errors.As(err, &valErr) { fmt.Printf("Field: %s\n", valErr.Field) } // Comparison with sentinel error if errors.Is(err, ErrNotFound) { fmt.Println("User not found") } } else { fmt.Println("User:", user) } } ``` > **errors.Is และ errors.As** > > ตั้งแต่ Go 1.13 ใช้ `errors.Is()` เพื่อเปรียบเทียบกับ sentinel error และ `errors.As()` เพื่อดึงประเภท error เฉพาะจากสาย error ที่ถูก wrap ## Goroutine: concurrency น้ำหนักเบา Goroutine เป็น thread น้ำหนักเบาที่จัดการโดย runtime ของ Go การเริ่ม goroutine ใช้หน่วยความจำเพียงไม่กี่ KB ```go // goroutines.go package main import ( "fmt" "sync" "time" ) func worker(id int, wg *sync.WaitGroup) { defer wg.Done() // Decrement counter when done fmt.Printf("Worker %d starting\n", id) time.Sleep(time.Second) fmt.Printf("Worker %d done\n", id) } func main() { var wg sync.WaitGroup // Launch 5 goroutines for i := 1; i <= 5; i++ { wg.Add(1) go worker(i, &wg) // 'go' prefix launches the goroutine } // Wait for all goroutines to complete wg.Wait() fmt.Println("All workers completed") } ``` `sync.WaitGroup` ช่วยให้รอจนกว่า goroutine หลายตัวจะทำงานเสร็จ นี่คือ pattern พื้นฐานสำหรับการทำงานแบบขนานใน Go ## Channel: การสื่อสารระหว่าง goroutine Channel เป็นท่อที่มีประเภทสำหรับการสื่อสารระหว่าง goroutine ช่วยให้มีการซิงโครไนซ์ที่ปลอดภัยและการแลกเปลี่ยนข้อมูล ```go // channels.go package main import ( "fmt" "time" ) func producer(ch chan<- int) { for i := 1; i <= 5; i++ { fmt.Println("Producing:", i) ch <- i // Send on channel time.Sleep(100 * time.Millisecond) } close(ch) // Close channel when done } func consumer(ch <-chan int, done chan<- bool) { for value := range ch { // Iterate until closed fmt.Println("Consuming:", value) } done <- true } func main() { ch := make(chan int) // Unbuffered channel done := make(chan bool) go producer(ch) go consumer(ch, done) <-done // Wait for consumer to finish fmt.Println("All done") } ``` ### Buffered channel และ select ```go // channels_advanced.go package main import ( "fmt" "time" ) func main() { // Buffered channel (capacity 3) buffered := make(chan int, 3) buffered <- 1 buffered <- 2 buffered <- 3 // buffered <- 4 // Would block since buffer is full fmt.Println(<-buffered) // 1 // Select: channel multiplexing ch1 := make(chan string) ch2 := make(chan string) go func() { time.Sleep(100 * time.Millisecond) ch1 <- "from ch1" }() go func() { time.Sleep(200 * time.Millisecond) ch2 <- "from ch2" }() // Wait for first available message for i := 0; i < 2; i++ { select { case msg1 := <-ch1: fmt.Println("Received:", msg1) case msg2 := <-ch2: fmt.Println("Received:", msg2) case <-time.After(500 * time.Millisecond): fmt.Println("Timeout!") } } } ``` > **ปรัชญาของ Go: CSP** > > Go ปฏิบัติตามโมเดล CSP (Communicating Sequential Processes): "อย่าสื่อสารโดยการแชร์หน่วยความจำ แต่จงแชร์หน่วยความจำโดยการสื่อสาร" Channel ป้องกัน race condition ## การทดสอบใน Go Go มี framework ทดสอบที่เรียบง่ายแต่มีประสิทธิภาพ ไฟล์ทดสอบลงท้ายด้วย `_test.go` ```go // calculator.go package calculator func Add(a, b int) int { return a + b } func Divide(a, b int) (int, error) { if b == 0 { return 0, errors.New("division by zero") } return a / b, nil } ``` ```go // calculator_test.go package calculator import ( "testing" ) // Basic test func TestAdd(t *testing.T) { result := Add(2, 3) expected := 5 if result != expected { t.Errorf("Add(2, 3) = %d; want %d", result, expected) } } // Table-driven tests (recommended pattern) func TestAddTableDriven(t *testing.T) { tests := []struct { name string a, b int expected int }{ {"positive numbers", 2, 3, 5}, {"negative numbers", -2, -3, -5}, {"zero", 0, 0, 0}, {"mixed", -5, 10, 5}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := Add(tt.a, tt.b) if result != tt.expected { t.Errorf("Add(%d, %d) = %d; want %d", tt.a, tt.b, result, tt.expected) } }) } } // Error test func TestDivideByZero(t *testing.T) { _, err := Divide(10, 0) if err == nil { t.Error("Expected error for division by zero") } } // Benchmark func BenchmarkAdd(b *testing.B) { for i := 0; i < b.N; i++ { Add(100, 200) } } ``` Test รันด้วย `go test ./...` และ benchmark ด้วย `go test -bench=.` ## HTTP: เว็บเซิร์ฟเวอร์แบบ minimalist Go เก่งในการสร้าง HTTP server ประสิทธิภาพสูงด้วย standard library ```go // server.go package main import ( "encoding/json" "log" "net/http" ) type User struct { ID int `json:"id"` Name string `json:"name"` } func main() { // Simple route http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello, Go!")) }) // JSON route http.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) { users := []User{ {ID: 1, Name: "Alice"}, {ID: 2, Name: "Bob"}, } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(users) }) // Route with method http.HandleFunc("/api/user", func(w http.ResponseWriter, r *http.Request) { switch r.Method { case "GET": w.Write([]byte("Get user")) case "POST": w.Write([]byte("Create user")) default: http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) } }) log.Println("Server starting on :8080") log.Fatal(http.ListenAndServe(":8080", nil)) } ``` เซิร์ฟเวอร์นี้จัดการการเชื่อมต่อพร้อมกันหลายพันรายการได้ด้วย goroutine แต่ละ request จะถูกประมวลผลโดยอัตโนมัติใน goroutine ของตัวเอง ## สรุป Go มอบแนวทางเชิงปฏิบัติสำหรับการพัฒนา backend: syntax เรียบง่าย คอมไพล์เร็ว concurrency แบบ native และเครื่องมือที่ยอดเยี่ยม สำหรับนักพัฒนา Java หรือ Python การเปลี่ยนผ่านต้องยอมรับข้อตกลงที่แตกต่างบางประการ (การจัดการข้อผิดพลาดแบบชัดเจน, generics ที่จำกัดก่อน Go 1.18) แต่ประโยชน์ด้านประสิทธิภาพและการบำรุงรักษาเห็นได้ทันที ### รายการตรวจสอบเพื่อเริ่มต้น - ✅ ติดตั้ง Go จากเว็บไซต์ทางการหรือ package manager - ✅ เชี่ยวชาญคำสั่ง `go build`, `go run`, `go test`, `go fmt` - ✅ เข้าใจความแตกต่างระหว่าง slice และ array - ✅ นำ pattern `if err != nil` มาใช้ในการจัดการข้อผิดพลาด - ✅ ใช้ goroutine และ channel สำหรับ concurrency - ✅ เขียน table-driven test ด้วย package `testing` ระบบนิเวศของ Go มีความสมบูรณ์ มี framework ยอดนิยมอย่าง Gin, Echo และ Fiber สำหรับพัฒนาเว็บ และเครื่องมืออย่าง Cobra สำหรับ CLI ด้วยรากฐานที่มั่นคงเหล่านี้ การสำรวจหัวข้อขั้นสูงอย่าง generics (Go 1.18+), package context และ pattern ของ concurrency จะเป็นเรื่องที่เข้าถึงได้ง่าย --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/th/blog/go/go-basics-java-python-developers