Series Go Backend: Biến, Hằng số và các Kiểu dữ liệu cơ bản
Go là một ngôn ngữ "Statically Typed" (kiểu tĩnh) tương tự như C++. Điều này có nghĩa là trình biên dịch (compiler) phải biết chính xác kiểu dữ liệu của mọi biến trước khi chương trình chạy. Tính khắt khe này giúp bạn phát hiện sớm các lỗi type mismatch ngay trong lúc code, thay vì để lọt bug ra production như các ngôn ngữ kiểu động (PHP, JavaScript).
1. Khai báo biến (Variables) và Zero Value
Trong Go, có 3 cách phổ biến nhất để khai báo một biến:
Cách 1: Khai báo đầy đủ với từ khóa var
Thường dùng khi bạn muốn khai báo biến nhưng chưa gán giá trị ngay lúc đó.
Go
var age int
var username string
var isActive bool
Cách 2: Type Inference (Suy luận kiểu)
Khai báo bằng var và gán luôn giá trị, Go sẽ tự đoán kiểu dữ liệu dựa trên giá trị được gán.
Go
var email = "admin@example.com" // Go tự hiểu đây là string
var maxConnections = 100 // Go tự hiểu đây là int
Cách 3: Cú pháp ngắn gọn := (Short variable declaration)
Đây là cách phổ biến nhất, dùng ở mọi nơi bên trong một hàm (không dùng được cho biến toàn cục ở level package).
Go
func processOrder() {
orderID := 1024
status := "PENDING"
}
Đặc sản của Go: Zero Value
Không giống như các ngôn ngữ khác (biến chưa khởi tạo sẽ mang giá trị
null,undefinedhoặc sinh ra lỗi bộ nhớ rác), Go sẽ gán một giá trị mặc định "an toàn" gọi là Zero Value cho biến vừa khai báo:
Numeric (
int,float,...):0
bool:false
string:""(chuỗi rỗng)Pointers, functions, interfaces, slices, channels, maps:
nil
2. Các Kiểu Dữ Liệu Nguyên Thủy (Primitive Types)
Nhóm số nguyên (Integer)
Go phân chia rất rõ ràng kích thước bộ nhớ của số nguyên:
-
int8,int16,int32,int64: Số nguyên có dấu (chứa được số âm). -
uint8,uint16,uint32,uint64: Số nguyên không dấu (chỉ số dương). -
intvàuint: Kích thước phụ thuộc vào hệ điều hành (32-bit trên HĐH 32-bit, 64-bit trên HĐH 64-bit).
Mẹo Backend: Khi thiết kế Struct map với Database, các trường ID khóa chính auto-increment thường được gán cứng kiểu int64 hoặc uint64 để tránh tràn số lượng bản ghi.
Nhóm số thực (Float)
float32,float64. Khi tính toán tiền tệ, tuyệt đối không dùng float để tránh sai số dấu phẩy động (nên dùng int lưu đơn vị nhỏ nhất, hoặc dùng các thư viện Decimal riêng).
Chuỗi và Boolean
-
bool: Chỉ nhậntruehoặcfalse. -
string: Chuỗi trong Go là immutable (không thể thay đổi nội dung sau khi đã khởi tạo) và được encode bằng chuẩn UTF-8 mặc định. -
byte: Là một alias củauint8, thường dùng để xử lý dữ liệu nhị phân (VD: đọc file, hash mật khẩu). -
rune: Là một alias củaint32, đại diện cho một ký tự Unicode (giúp xử lý chính xác các ngôn ngữ có dấu, tiếng Trung, tiếng Nhật).
3. Không có chuyện tự động ép kiểu (Implicit Type Conversion)
Tính khắt khe của Go thể hiện rõ nhất ở đây. Khác với C++ có thể tự ép kiểu ngầm định khi cộng int với float, Go tuyệt đối cấm điều này. Bạn phải chủ động ép kiểu (Casting).
Go
var price int = 100
var tax float64 = 5.5
// Lỗi: invalid operation: price + tax (mismatched types int and float64)
// total := price + tax
// Code chuẩn: Ép price về float64 trước khi cộng
total := float64(price) + tax
4. Hằng số (Constants) và Tuyệt chiêu iota
Hằng số được khai báo bằng từ khóa const. Giá trị của nó không thể thay đổi sau khi khởi tạo và phải được xác định ngay lúc biên dịch.
Go
const Pi = 3.14
const MaxRetryCount int = 3
Trong backend, chúng ta rất thường xuyên phải tạo các Enum (ví dụ: Trạng thái đơn hàng, Role người dùng). Go không có từ khóa enum, nhưng cung cấp một keyword cực kỳ mạnh mẽ là iota để tự động tăng giá trị số nguyên trong một block const.
Go
const (
OrderStatusPending = iota // Giá trị = 0
OrderStatusProcessing // Giá trị = 1 (Tự động kế thừa quy luật và tăng lên 1)
OrderStatusDelivered // Giá trị = 2
OrderStatusCancelled // Giá trị = 3
)
const (
RoleGuest = iota + 1 // Bắt đầu từ 1
RoleUser // 2
RoleAdmin // 3
)
Việc sử dụng iota giúp source code sạch sẽ, dễ bảo trì và hạn chế rủi ro phải sửa số thủ công khi chèn thêm một trạng thái mới vào giữa danh sách.
All rights reserved