Go: พื้นฐานสำหรับนักพัฒนา Java/Python ในปี 2026
เรียนรู้ Go อย่างรวดเร็วโดยใช้ประสบการณ์จาก Java หรือ Python Goroutine, channel, interface และ pattern สำคัญสำหรับการเปลี่ยนผ่านอย่างราบรื่น

Go (หรือ Golang) ได้สถาปนาตนเองเป็นภาษาที่เลือกใช้สำหรับ microservice, เครื่องมือ CLI และระบบแบบกระจาย สร้างโดย Google ในปี 2009 ผสมผสานความเรียบง่ายของ Python เข้ากับประสิทธิภาพระดับ C สำหรับนักพัฒนาที่มาจาก Java หรือ Python การเปลี่ยนมาใช้ Go นั้นราบรื่นอย่างน่าประหลาดใจเมื่อแนวคิดหลักเข้าที่แล้ว
Go เป็นรากฐานของ Docker, Kubernetes, Terraform และโครงสร้างพื้นฐานคลาวด์จำนวนมาก การคอมไพล์ที่รวดเร็ว รองรับ concurrency แบบ native และการ deploy เป็นไฟล์ binary เดียว ทำให้ Go เหมาะสำหรับการพัฒนา backend สมัยใหม่
การติดตั้งและตั้งค่า Go
การติดตั้ง Go ทำได้ง่ายและสม่ำเสมอบนทุกแพลตฟอร์ม เครื่องมือ go จัดการการคอมไพล์ dependency และการทดสอบ
# 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 ต่าง ๆ
# 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 ช่วยให้เห็นความแตกต่างได้ชัดเจน
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 แต่มีการอนุมานประเภทที่ยอดเยี่ยม ประเภทพื้นฐานครอบคลุมกรณีใช้งานส่วนใหญ่
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)
}ต่างจาก Java หรือ Python ตรงที่ Go จะกำหนดค่าเริ่มต้นให้ตัวแปรเป็น "zero value" โดยอัตโนมัติ: 0 สำหรับตัวเลข, "" สำหรับ string, false สำหรับ bool, nil สำหรับ pointer และ slice
ฟังก์ชันและการคืนค่าหลายค่า
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
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())
}ใช้ pointer receiver (*User) เมื่อ method เปลี่ยนแปลงสถานะหรือเมื่อ struct มีขนาดใหญ่ ใช้ value receiver (User) สำหรับ method อ่านอย่างเดียวบน struct ที่เบา
Interface: polymorphism แบบ implicit
Interface ใน Go ถูก implement แบบ implicit ประเภทหนึ่งจะเป็นไปตาม interface ถ้า implement method ทั้งหมดของมัน โดยไม่ต้องประกาศอย่างชัดเจน
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 การสอดคล้องเป็นแบบโครงสร้าง ไม่ใช่แบบชื่อ
พร้อมที่จะพิชิตการสัมภาษณ์ Go แล้วหรือยังครับ?
ฝึกฝนด้วยตัวจำลองแบบโต้ตอบ, flashcards และแบบทดสอบเทคนิคครับ
Slice และ map: คอลเลกชันแบบไดนามิก
Slice เป็นมุมมองแบบไดนามิกบน array และ map เป็น hash table ในตัว
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 ข้อผิดพลาดเป็นค่าที่คืนกลับอย่างชัดเจน บังคับให้จัดการอย่างเข้มงวด
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)
}
}ตั้งแต่ Go 1.13 ใช้ errors.Is() เพื่อเปรียบเทียบกับ sentinel error และ errors.As() เพื่อดึงประเภท error เฉพาะจากสาย error ที่ถูก wrap
Goroutine: concurrency น้ำหนักเบา
Goroutine เป็น thread น้ำหนักเบาที่จัดการโดย runtime ของ Go การเริ่ม goroutine ใช้หน่วยความจำเพียงไม่กี่ KB
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 ช่วยให้มีการซิงโครไนซ์ที่ปลอดภัยและการแลกเปลี่ยนข้อมูล
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
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 (Communicating Sequential Processes): "อย่าสื่อสารโดยการแชร์หน่วยความจำ แต่จงแชร์หน่วยความจำโดยการสื่อสาร" Channel ป้องกัน race condition
การทดสอบใน Go
Go มี framework ทดสอบที่เรียบง่ายแต่มีประสิทธิภาพ ไฟล์ทดสอบลงท้ายด้วย _test.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
}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
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 จะเป็นเรื่องที่เข้าถึงได้ง่าย
แท็ก
แชร์
บทความที่เกี่ยวข้อง

สัมภาษณ์เทคนิค Go: Goroutine, Channel และ Concurrency
คำถามสัมภาษณ์เทคนิค Go เกี่ยวกับ goroutine, channel และ concurrency pattern ต่างๆ ตัวอย่างโค้ด ข้อผิดพลาดที่พบบ่อย และคำตอบระดับผู้เชี่ยวชาญสำหรับเตรียมสัมภาษณ์เทคนิค Go ปี 2026

คำถามสัมภาษณ์ Backend Node.js: คู่มือฉบับสมบูรณ์ 2026
25 คำถามสัมภาษณ์ Backend Node.js ที่พบบ่อยที่สุด Event loop, async/await, streams, clustering และประสิทธิภาพอธิบายพร้อมคำตอบโดยละเอียด

Spring Boot 3.4: ฟีเจอร์ใหม่ทั้งหมดอธิบายครบถ้วน
Spring Boot 3.4 นำเสนอ structured logging แบบ native, virtual threads ที่ขยายเพิ่ม, graceful shutdown เป็นค่าเริ่มต้น และ MockMvcTester คู่มือฉบับสมบูรณ์ของฟีเจอร์ใหม่