Go Phase 1: Cơ Bản - Cài Đặt, Cú Pháp & Kiểu Dữ Liệu

Chào mừng bạn đến với Phase 1 của Go Learning Roadmap! Hướng dẫn toàn diện này bao gồm mọi thứ bạn cần để bắt đầu với Go - từ cài đặt đến viết chương trình hoàn chỉnh đầu tiên.
Bạn Sẽ Học Được Gì
✅ Cài đặt Go và thiết lập môi trường phát triển
✅ Hiểu cấu trúc project và modules của Go
✅ Nắm vững biến, hằng và kiểu dữ liệu cơ bản
✅ Viết luồng điều khiển với if/else, switch và for loops
✅ Tạo hàm với nhiều giá trị trả về
✅ Làm việc với arrays, slices và maps
✅ Sử dụng pointers để làm việc với bộ nhớ hiệu quả
Phần 1: Cài Đặt Go
macOS
# Sử dụng Homebrew (Khuyến nghị)
brew install go
# Xác minh cài đặt
go versionLinux
# Tải phiên bản mới nhất
wget https://go.dev/dl/go1.22.0.linux-amd64.tar.gz
# Giải nén
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.22.0.linux-amd64.tar.gz
# Thêm vào PATH (~/.bashrc hoặc ~/.zshrc)
export PATH=$PATH:/usr/local/go/bin
# Xác minh
go versionWindows
- Tải installer
.msitừ go.dev/dl - Chạy installer
- Mở Command Prompt mới
- Xác minh với
go version
Phần 2: Thiết Lập Môi Trường
VS Code Setup
- Cài đặt VS Code
- Cài đặt Go Extension (Go Team at Google)
- Mở Command Palette → "Go: Install/Update Tools" → Chọn tất cả
Các công cụ quan trọng:
gopls- Language serverdlv- Debuggergofumpt- Formattergolangci-lint- Linter
Phần 3: Chương Trình Go Đầu Tiên
# Tạo project
mkdir hello-go && cd hello-go
go mod init hello-goTạo main.go:
package main
import "fmt"
func main() {
fmt.Println("Hello, Go!")
}# Chạy
go run main.go
# Build binary
go build -o hello
./helloCác Lệnh Go Quan Trọng
| Lệnh | Mô tả |
|---|---|
go run | Compile và chạy |
go build | Compile tạo binary |
go fmt | Format code |
go vet | Phát hiện lỗi |
go test | Chạy tests |
go mod init | Khởi tạo module |
go mod tidy | Dọn dẹp dependencies |
Phần 4: Biến và Hằng
Khai Báo Biến
// Cách 1: var với kiểu tường minh
var name string = "Alice"
var age int = 30
// Cách 2: var với type inference
var city = "Tokyo"
// Cách 3: Short declaration (phổ biến nhất)
country := "Japan"
isActive := true
// Cách 4: Nhiều biến
var x, y, z int = 1, 2, 3
a, b := "hello", 42
// Cách 5: var block
var (
firstName = "Bob"
lastName = "Smith"
)Zero Values
Biến chưa khởi tạo nhận zero value:
| Kiểu | Zero Value |
|---|---|
int, float64 | 0 |
bool | false |
string | "" |
| pointers, slices, maps | nil |
Hằng Số
const Pi = 3.14159
// Hằng block
const (
StatusOK = 200
StatusNotFound = 404
)
// iota: tự động tăng
const (
Sunday = iota // 0
Monday // 1
Tuesday // 2
)
// iota với biểu thức
const (
_ = iota
KB = 1 << (10 * iota) // 1024
MB // 1048576
GB // 1073741824
)Phần 5: Kiểu Dữ Liệu Cơ Bản
Kiểu Số
// Integers
var i int = 42 // platform-dependent (32 hoặc 64 bit)
var i64 int64 = 9223372036854775807
// Unsigned
var u8 uint8 = 255 // 0-255
// Floating point
var f64 float64 = 3.14159
// Complex
var c128 complex128 = 1.5 + 2.5iStrings và Runes
s := "Hello, 世界"
// Độ dài bytes (không phải ký tự!)
len(s) // 13 bytes
// Độ dài runes (ký tự)
utf8.RuneCountInString(s) // 9 ký tự
// Duyệt theo rune (đúng cách)
for _, r := range s {
fmt.Printf("%c", r)
}
// Rune = int32 cho Unicode
var r rune = '世'Chuyển Đổi Kiểu
Go yêu cầu chuyển đổi tường minh:
var i int = 42
var f float64 = float64(i)
// String ↔ Number
n, _ := strconv.Atoi("123") // string → int
str := strconv.Itoa(456) // int → stringPhần 6: Luồng Điều Khiển
If/Else
// If với khởi tạo (idiomatic Go!)
if value := compute(); value > 10 {
fmt.Println("Value:", value)
}
// Pattern xử lý lỗi
if err := doSomething(); err != nil {
return err
}Switch
// Switch cơ bản
switch day {
case "Monday":
fmt.Println("Đầu tuần")
case "Saturday", "Sunday":
fmt.Println("Cuối tuần!")
default:
fmt.Println("Giữa tuần")
}
// Switch không điều kiện (thay if-else chain)
switch {
case hour < 12:
fmt.Println("Chào buổi sáng!")
case hour < 17:
fmt.Println("Chào buổi chiều!")
default:
fmt.Println("Chào buổi tối!")
}
// Type switch
switch t := i.(type) {
case int:
fmt.Printf("Integer: %d\n", t)
case string:
fmt.Printf("String: %s\n", t)
}Lưu ý: Không cần break - các case không "fall through" mặc định.
For Loops
Go chỉ có một cấu trúc lặp: for
// Traditional for
for i := 0; i < 5; i++ {
fmt.Print(i)
}
// While-style
for count < 3 {
count++
}
// Infinite loop
for {
if condition {
break
}
}
// Range over slices
for index, value := range fruits {
fmt.Printf("%d: %s\n", index, value)
}
// Range - chỉ value
for _, fruit := range fruits {
fmt.Println(fruit)
}
// Range over maps
for key, value := range ages {
fmt.Printf("%s: %d\n", key, value)
}Defer
func cleanup() {
fmt.Println("Mở file...")
defer fmt.Println("Đóng file...") // Luôn chạy khi hàm kết thúc
fmt.Println("Ghi file...")
}Sử dụng defer cho: đóng files, unlock mutexes, cleanup resources.
Phần 7: Functions
Hàm Cơ Bản
// Hàm đơn giản
func greet(name string) {
fmt.Println("Hello,", name)
}
// Hàm với return
func add(a, b int) int {
return a + b
}
// Nhiều giá trị trả về
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("chia cho 0")
}
return a / b, nil
}
// Named return values
func rectangle(w, h float64) (area, perimeter float64) {
area = w * h
perimeter = 2 * (w + h)
return
}Variadic Functions
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
sum(1, 2, 3) // 6
sum(1, 2, 3, 4, 5) // 15
numbers := []int{10, 20, 30}
sum(numbers...) // 60Closures
func makeCounter() func() int {
count := 0
return func() int {
count++
return count
}
}
counter := makeCounter()
counter() // 1
counter() // 2
counter() // 3Phần 8: Pointers
x := 42
var p *int = &x // p chứa địa chỉ của x
fmt.Println(*p) // 42 (dereferencing)
*p = 100 // Thay đổi x qua pointer
fmt.Println(x) // 100Pointers với Functions
// Pass by value - không thay đổi original
func doubleValue(x int) {
x = x * 2
}
// Pass by pointer - thay đổi original
func doublePointer(x *int) {
*x = *x * 2
}
n := 10
doubleValue(n) // n vẫn là 10
doublePointer(&n) // n = 20Khi nào dùng pointers:
- Cần thay đổi giá trị gốc
- Truyền structs lớn (tránh copy)
- Cần biểu thị "không có giá trị" với nil
Xem thêm:
- Pointer Receiver vs Value Receiver
- So Sánh Pointer Go và C++ - So sánh cách tiếp cận an toàn của Go với C++
Phần 9: Arrays và Slices
Arrays (Kích thước cố định)
var arr [5]int // [0 0 0 0 0]
arr2 := [5]int{1, 2, 3, 4, 5}
arr3 := [...]int{10, 20, 30} // Compiler đếm
// Arrays là VALUE types - copy tạo array mới
arr4 := arr2
arr4[0] = 999
fmt.Println(arr2[0]) // Vẫn là 1!Slices (Động, Reference Type)
// Tạo với make
s := make([]int, 5) // length 5, capacity 5
s2 := make([]int, 3, 10) // length 3, capacity 10
// Slice literal
s3 := []int{1, 2, 3, 4, 5}
// Slice từ array
arr := [5]int{10, 20, 30, 40, 50}
slice := arr[1:4] // [20 30 40]
// Slices là REFERENCE types
original := []int{1, 2, 3}
reference := original
reference[0] = 999
fmt.Println(original[0]) // 999 (đã thay đổi!)Slice Operations
// Append
s := []int{1, 2, 3}
s = append(s, 4)
s = append(s, 5, 6, 7)
// Append slice khác
more := []int{8, 9}
s = append(s, more...)
// Copy
dst := make([]int, len(src))
copy(dst, src)
// Delete phần tử tại index i
s = append(s[:i], s[i+1:]...)Quan trọng: Đọc bài Never Use Arrays in Go
Phần 10: Maps
// Tạo với make
ages := make(map[string]int)
ages["Alice"] = 30
// Map literal
scores := map[string]int{
"Alice": 95,
"Bob": 87,
}
// Kiểm tra key tồn tại
score, exists := scores["David"]
if exists {
fmt.Println(score)
}
// Pattern ngắn gọn
if s, ok := scores["Carol"]; ok {
fmt.Println(s)
}
// Xóa key
delete(scores, "Bob")
// Duyệt (thứ tự ngẫu nhiên!)
for name, score := range scores {
fmt.Printf("%s: %d\n", name, score)
}
// nil map - đọc được, KHÔNG ghi được
var nilMap map[string]int
nilMap["key"] = 1 // PANIC!Map làm Set
set := make(map[string]struct{})
for _, item := range items {
set[item] = struct{}{}
}
// Lấy unique items
for item := range set {
fmt.Println(item)
}Phần 11: Structs
// Định nghĩa struct
type Person struct {
FirstName string
LastName string
Age int
}
// Tạo struct
p1 := Person{
FirstName: "Alice",
LastName: "Smith",
Age: 30,
}
// Truy cập fields
fmt.Println(p1.FirstName)
p1.Age = 31
// Pointer to struct
p2 := &Person{FirstName: "Bob"}
fmt.Println(p2.FirstName) // Không cần -> như C!Struct Embedding (Composition)
type Address struct {
City string
Country string
}
type Employee struct {
Name string
Address // Embedded
}
emp := Employee{
Name: "Alice",
Address: Address{City: "New York"},
}
// Truy cập trực tiếp (promoted)
fmt.Println(emp.City) // New York
fmt.Println(emp.Address.City) // Cũng đượcXem thêm: Composition Over Inheritance
Bài Tập Thực Hành
Bài 1: Temperature Converter
func celsiusToFahrenheit(c float64) float64 {
return c*9/5 + 32
}
func fahrenheitToCelsius(f float64) float64 {
return (f - 32) * 5 / 9
}Bài 2: Word Counter
func wordCount(text string) map[string]int {
words := strings.Fields(strings.ToLower(text))
counts := make(map[string]int)
for _, word := range words {
counts[word]++
}
return counts
}Bài 3: FizzBuzz
func fizzBuzz(n int) string {
switch {
case n%15 == 0:
return "FizzBuzz"
case n%3 == 0:
return "Fizz"
case n%5 == 0:
return "Buzz"
default:
return fmt.Sprintf("%d", n)
}
}Lỗi Thường Gặp
1. Shadowing Variables
// SAI: err bị shadow
var err error
if condition {
result, err := doSomething() // err MỚI!
}
// ĐÚNG
var err error
if condition {
var result int
result, err = doSomething()
}2. Loop Variable Capture
// SAI: Tất cả goroutines thấy giá trị cuối
for i := 0; i < 3; i++ {
go func() {
fmt.Println(i) // In 3, 3, 3
}()
}
// ĐÚNG: Copy biến
for i := 0; i < 3; i++ {
i := i
go func() {
fmt.Println(i) // In 0, 1, 2
}()
}3. Nil Map Write
// SAI
var m map[string]int
m["key"] = 1 // PANIC!
// ĐÚNG
m := make(map[string]int)
m["key"] = 1Tiếp Theo
Chúc mừng bạn đã hoàn thành Phase 1! Bạn đã có nền tảng vững chắc về Go.
Trong Phase 2: Core Go Concepts, bạn sẽ học:
- Structs và methods chuyên sâu
- Interfaces và polymorphism
- Error handling patterns
- Package organization
Bài viết liên quan:
- Go Learning Roadmap
- Never Use Arrays in Go
- Pointer Receiver vs Value Receiver
- Composition Over Inheritance
- So Sánh Pointer Go và C++ - So sánh pointer giữa các ngôn ngữ
Tóm Tắt
Trong bài này, bạn đã học:
✅ Cài đặt: Thiết lập Go và môi trường phát triển
✅ Biến: Khai báo, zero values, hằng và iota
✅ Kiểu dữ liệu: Integers, floats, strings, booleans
✅ Luồng điều khiển: if/else, switch, for loops, defer
✅ Functions: Nhiều returns, variadic, closures
✅ Pointers: Địa chỉ bộ nhớ và dereferencing
✅ Arrays & Slices: Mảng cố định vs động
✅ Maps: Hash tables cho key-value storage
✅ Structs: Custom types và embedding
Bạn đã sẵn sàng chuyển sang Phase 2 và khám phá interfaces, error handling và packages!
Happy coding! 🚀
📬 Đăng ký nhận bản tin
Nhận những bài viết mới nhất qua email mỗi tuần. Không spam, hủy đăng ký bất cứ lúc nào.
Chúng tôi tôn trọng quyền riêng tư của bạn. Hủy đăng ký bất cứ lúc nào.
💬 Comments
Đăng nhập để bình luận
Chúng tôi sẽ không đăng bất cứ điều gì mà không có sự cho phép của bạn.