0

Go Zero to Hero - Bài 8: Ép kiểu (Type Casting) trong Golang

Trong lập trình Backend, việc xử lý dữ liệu đến từ nhiều nguồn khác nhau (Database, HTTP Request, JSON payload) đòi hỏi bạn phải thao tác với việc ép kiểu dữ liệu liên tục. Triết lý của Go đối với việc này là tuyệt đối an toàn và rõ ràng.


1. Sự khắt khe của Go: Không có ép kiểu ngầm định

Quy tắc tối thượng trong Go: Không bao giờ có chuyện tự động ép kiểu giữa các biến khác loại, dù chúng có họ hàng gần với nhau đi chăng nữa.

Hãy xem thử đoạn code sau, trông rất bình thường nhưng sẽ khiến trình biên dịch của Go "nổi điên":

func main() {
    var a int = 10
    var b float64 = 5.5
    
    // LỖI! Invalid operation: a + b (mismatched types int and float64)
    var sum = a + b 
}

Go sẽ không tự động biến a thành float64 để cộng với b. Nó bắt bạn phải nói rõ: "Tôi muốn biến a thành kiểu số thực rồi mới cộng". Sự khắt khe này giúp hệ thống của bạn triệt tiêu hoàn toàn những bug tiềm ẩn liên quan đến sai số hay tràn bộ nhớ ở thời điểm Runtime.


2. Type Conversion: Ép kiểu cơ bản (Cú pháp T(v))

Để ép kiểu một giá trị v sang kiểu dữ liệu T, Go sử dụng cú pháp rất đơn giản: T(v).

Quay lại ví dụ trên, để đoạn code chạy được, bạn phải ép kiểu rõ ràng:

func main() {
    var a int = 10
    var b float64 = 5.5
    
    // Cách 1: Ép int sang float64
    var sum1 float64 = float64(a) + b // Kết quả: 15.5
    
    // Cách 2: Ép float64 sang int
    var sum2 int = a + int(b) // Kết quả: 15 (Số 5.5 bị cắt mất phần thập phân)
}

⚠️ Lưu ý sinh tử: Khi bạn ép kiểu từ vùng nhớ lớn xuống vùng nhớ nhỏ (ví dụ từ int64 xuống int8), nếu giá trị vượt quá giới hạn của int8 (từ -128 đến 127), dữ liệu sẽ bị tràn (overflow) và sinh ra một con số vô nghĩa. Hãy luôn cẩn thận khi ép kiểu xuống (Down-casting)!


3. Chuyển đổi qua lại với Chuỗi: Gói strconv

Trong thực tế làm Backend API, dữ liệu bạn nhận được từ Client (qua Query Params, JSON body) thường nằm ở dạng Chuỗi (string). Làm sao để biến "100" thành số 100? Bạn không thể dùng cú pháp int("100") được.

Đó là lúc gói thư viện tiêu chuẩn strconv (String Conversion) tỏa sáng.

Chuỗi sang Số (String to Int/Float)

Hàm được dùng nhiều nhất là strconv.Atoi (ASCII to Integer).

package main

import (
    "fmt"
    "strconv"
)

func main() {
    strPrice := "250000"
    
    // Hàm Atoi trả về 2 giá trị: kết quả (số int) và lỗi (error)
    price, err := strconv.Atoi(strPrice)
    
    if err != nil {
        fmt.Println("Chuỗi không phải là số hợp lệ!")
    } else {
        fmt.Println("Giá tiền:", price)
    }
}

Để chuyển chuỗi sang số thập phân, bạn dùng strconv.ParseFloat():

piString := "3.14159"
piFloat, _ := strconv.ParseFloat(piString, 64) // 64 là đại diện cho float64

Số sang Chuỗi (Int/Float to String)

Ngược lại với Atoi, chúng ta có hàm Itoa (Integer to ASCII):

userID := 9981
strID := strconv.Itoa(userID) // Kết quả: "9981"

4. Type Assertion: Ép kiểu với interface{}

(Mặc dù chúng ta chưa học sâu về Interface, nhưng đây là một khái niệm bạn sẽ gặp ngay khi làm việc với JSON hay các thư viện ngoài).

Trong Go, interface{} (hoặc any từ Go 1.18) là một kiểu dữ liệu có thể chứa BẤT KỲ thứ gì (int, string, struct...). Khi bạn nhận một biến kiểu interface{}, bạn cần phải "khẳng định" (assert) kiểu thực sự của nó trước khi sử dụng.

Cú pháp: value, ok := variable.(Type)

func main() {
    var rawData interface{} = "Đây là một chuỗi"
    
    // Khẳng định rawData là kiểu string
    text, ok := rawData.(string)
    
    if ok {
        fmt.Println("Đã ép kiểu thành công:", text)
    } else {
        fmt.Println("Ép kiểu thất bại, đây không phải là string")
    }
}

Chốt chặn an toàn: Biến ok (kiểu boolean) là một chốt chặn an toàn cực hay của Go. Nếu rawData không phải là chuỗi, ok sẽ trả về false và chương trình vẫn chạy bình thường. Nếu bạn viết tắt text := rawData.(string) mà dữ liệu thực tế lại là số nguyên, chương trình của bạn sẽ bị Panic (Crash sập server) ngay lập tức.


Tổng kết

Tóm lại, tư duy xử lý kiểu dữ liệu trong Go có thể gói gọn trong 3 ý:

  1. Chủ động và Rõ ràng: Mọi sự chuyển đổi kiểu dữ liệu cơ bản đều dùng cú pháp T(v).
  2. Làm bạn với strconv: Bất cứ khi nào cần biến Chuỗi thành Số hoặc ngược lại, hãy nhớ import gói strconv.
  3. An toàn là trên hết: Khi làm việc với interface{}, luôn dùng cặp value, ok để kiểm tra Type Assertion, tuyệt đối không chủ quan để ứng dụng bị crash.

All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.