Go: Kiến thức cơ bản cho lập trình viên Java/Python năm 2026
Học Go nhanh chóng bằng cách tận dụng kinh nghiệm Java hoặc Python. Goroutine, channel, interface và các pattern thiết yếu cho quá trình chuyển đổi suôn sẻ.

Go (hay Golang) đã khẳng định vị thế là ngôn ngữ hàng đầu cho microservice, công cụ CLI và hệ thống phân tán. Được Google tạo ra vào năm 2009, Go kết hợp sự đơn giản của Python với hiệu năng của C. Đối với lập trình viên chuyển từ Java hoặc Python, quá trình chuyển sang Go diễn ra suôn sẻ đáng ngạc nhiên khi các khái niệm cốt lõi được nắm vững.
Go là nền tảng của Docker, Kubernetes, Terraform và vô số hạ tầng cloud khác. Biên dịch nhanh, hỗ trợ concurrency tự nhiên và triển khai bằng một file binary duy nhất khiến Go trở thành lựa chọn lý tưởng cho phát triển backend hiện đại.
Cài đặt và cấu hình Go
Cài đặt Go rất đơn giản và nhất quán trên mọi nền tảng. Công cụ go quản lý biên dịch, dependency và kiểm thử.
# 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/amd64Cấu trúc dự án Go tuân theo các quy ước nghiêm ngặt nhưng đơn giản. File go.mod định nghĩa module và các 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 automaticallyChương trình Go đầu tiên
Dưới đây là chương trình đơn giản minh họa cú pháp cơ bản của Go. So sánh với Java và Python giúp hình dung rõ các điểm khác biệt.
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)
}Điều dễ nhận thấy ngay: không có dấu chấm phẩy, không có dấu ngoặc quanh điều kiện và suy luận kiểu với :=. Go ưu tiên sự ngắn gọn mà không hy sinh tính dễ đọc.
Biến và các kiểu dữ liệu cơ bản
Go có kiểu tĩnh nhưng cung cấp khả năng suy luận kiểu xuất sắc. Các kiểu cơ bản đáp ứng hầu hết các trường hợp sử dụng.
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)
}Khác với Java hay Python, Go tự động khởi tạo biến với "giá trị zero": 0 cho số, "" cho string, false cho bool, nil cho pointer và slice.
Hàm và trả về nhiều giá trị
Go cho phép trả về nhiều giá trị cùng lúc, tính năng được sử dụng rộng rãi cho xử lý lỗi.
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 và method
Struct là khối xây dựng cơ bản cho các kiểu tùy chỉnh trong Go. Method được gắn với kiểu thông qua 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())
}Sử dụng pointer receiver (*User) khi method thay đổi trạng thái hoặc khi struct có kích thước lớn. Sử dụng value receiver (User) cho method chỉ đọc trên struct nhẹ.
Interface: đa hình ngầm định
Interface trong Go được triển khai ngầm định. Một kiểu thỏa mãn interface nếu triển khai tất cả method của nó, không cần khai báo tường minh.
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)
}
}Cách tiếp cận này khác biệt cơ bản so với Java, nơi implements là bắt buộc. Trong Go, sự tuân thủ mang tính cấu trúc, không phải danh nghĩa.
Sẵn sàng chinh phục phỏng vấn Go?
Luyện tập với mô phỏng tương tác, flashcards và bài kiểm tra kỹ thuật.
Slice và map: collection động
Slice là view động trên array, và map là hash table tích hợp sẵn.
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)
}
}Xử lý lỗi theo phong cách Go
Go không có exception. Lỗi là giá trị được trả về tường minh, buộc phải xử lý nghiêm ngặt.
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)
}
}Từ Go 1.13, errors.Is() được dùng để so sánh với sentinel error và errors.As() để trích xuất kiểu lỗi cụ thể từ chuỗi error được bọc.
Goroutine: concurrency nhẹ
Goroutine là luồng nhẹ được quản lý bởi runtime Go. Khởi chạy goroutine chỉ tốn vài KB bộ nhớ.
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 cho phép chờ nhiều goroutine hoàn thành. Đây là pattern cơ bản cho xử lý song song trong Go.
Channel: giao tiếp giữa các goroutine
Channel là kênh có kiểu để giao tiếp giữa các goroutine. Channel đảm bảo đồng bộ an toàn và trao đổi dữ liệu.
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")
}Channel có bộ đệm và 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 tuân theo mô hình CSP (Communicating Sequential Processes): "Đừng giao tiếp bằng cách chia sẻ bộ nhớ; hãy chia sẻ bộ nhớ bằng cách giao tiếp." Channel ngăn chặn race condition.
Testing trong Go
Go tích hợp framework testing tối giản nhưng hiệu quả. File test có đuôi _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 được chạy bằng go test ./... và benchmark bằng go test -bench=..
HTTP: web server tối giản
Go vượt trội trong việc tạo server HTTP hiệu năng cao với thư viện chuẩn.
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))
}Server này xử lý hàng nghìn kết nối đồng thời nhờ goroutine. Mỗi request tự động được xử lý trong goroutine riêng.
Kết luận
Go mang đến cách tiếp cận thực dụng cho phát triển backend: cú pháp đơn giản, biên dịch nhanh, concurrency tự nhiên và công cụ tuyệt vời. Đối với lập trình viên Java hoặc Python, quá trình chuyển đổi đòi hỏi chấp nhận một số quy ước khác biệt (xử lý lỗi tường minh, generics hạn chế trước Go 1.18), nhưng lợi ích về hiệu năng và khả năng bảo trì được thể hiện ngay lập tức.
Danh sách kiểm tra để bắt đầu
- ✅ Cài đặt Go từ trang chính thức hoặc trình quản lý gói
- ✅ Thành thạo các lệnh
go build,go run,go test,go fmt - ✅ Hiểu sự khác biệt giữa slice và array
- ✅ Áp dụng pattern
if err != nilcho xử lý lỗi - ✅ Sử dụng goroutine và channel cho concurrency
- ✅ Viết table-driven test với package
testing
Bắt đầu luyện tập!
Kiểm tra kiến thức với mô phỏng phỏng vấn và bài kiểm tra kỹ thuật.
Hệ sinh thái Go đã trưởng thành, với các framework phổ biến như Gin, Echo và Fiber cho phát triển web, cùng công cụ như Cobra cho CLI. Với nền tảng vững chắc này, việc khám phá các chủ đề nâng cao như generics (Go 1.18+), package context và các pattern concurrency trở nên dễ tiếp cận.
Thẻ
Chia sẻ
Bài viết liên quan

Phỏng vấn kỹ thuật Go: Goroutine, Channel và Concurrency
Các câu hỏi phỏng vấn kỹ thuật Go về goroutine, channel và các pattern concurrency. Ví dụ code, bẫy thường gặp và câu trả lời chuyên gia để chuẩn bị phỏng vấn kỹ thuật Go năm 2026.

Cau Hoi Phong Van Backend Node.js: Huong Dan Day Du 2026
25 cau hoi phong van backend Node.js thuong gap nhat. Event loop, async/await, streams, clustering va hieu suat duoc giai thich chi tiet.

Spring Boot 3.4: Tất cả tính năng mới được giải thích chi tiết
Spring Boot 3.4 mang đến structured logging native, virtual threads mở rộng, graceful shutdown mặc định và MockMvcTester. Hướng dẫn đầy đủ các tính năng mới.