Sửa lỗi 'invalid operation: mismatched types' trong các phép tính Go

beginner🔷 Go2026-05-27| Go (mọi phiên bản), Linux/macOS/Windows

Error Message

invalid operation: x + y (mismatched types int and int64)
#go#kiểu-dữ-liệu#ép-kiểu#không-khớp

Bối cảnh

Tôi vừa gặp một trở ngại khi viết script Go để theo dõi việc tải tệp lên. Tôi đã thử so sánh 4.096 byte đã đọc với tổng dung lượng tệp 2,5 GB. Đến từ Python hay JavaScript, tôi mong đợi trình biên dịch sẽ tự "xử lý" vì cả hai giá trị rõ ràng đều là số nguyên. Thay vào đó, bản build bị lỗi ngay lập tức với lỗi không khớp kiểu dữ liệu.

Hệ thống kiểu dữ liệu của Go rất nghiêm ngặt. Nó từ chối thực hiện chuyển đổi kiểu ngầm định (coercion), ngay cả giữa các kiểu số trông giống hệt nhau như intint64. Nếu bạn cố gắng cộng, trừ hoặc so sánh các biến này, trình biên dịch sẽ báo lỗi:

invalid operation: x + y (mismatched types int and int64)

Quá trình gỡ lỗi

Lỗi thường xuất hiện trong đoạn mã giống như ví dụ này:

package main

import (
	"fmt"
	"os"
)

func main() {
	var count int = 10
	fileInfo, _ := os.Stat("data.csv")
	size := fileInfo.Size() // Hàm này trả về một int64

	// Bản build bị lỗi ở đây
	if count < size {
		fmt.Println("Đang xử lý...")
	}
}

Để xem chuyện gì đang xảy ra bên dưới, hãy sử dụng động từ %T trong fmt.Printf. Nó là cứu cánh khi bạn không chắc chắn một hàm thư viện cụ thể đang trả về kết quả gì:

fmt.Printf("kiểu của count: %T\n", count)
fmt.Printf("kiểu của size: %T\n", size)

Kết quả xác nhận sự xung đột:

  • count là một int tiêu chuẩn
  • size là một int64

Giải pháp

Vì Go sẽ không tự lấp đầy khoảng cách cho bạn, bạn phải tự điều chỉnh các kiểu dữ liệu một cách thủ công. Bạn có hai chiến lược chính tùy thuộc vào yêu cầu an toàn của mình.

Cách 1: Ép kiểu nhỏ hơn sang int64 (Khuyên dùng)

Đây gần như luôn là bước đi tốt nhất. Chuyển đổi một int tiêu chuẩn sang int64 là an toàn vì kiểu dữ liệu mục tiêu có kích thước lớn hơn. Bạn sẽ không gặp rủi ro bị lỗi tràn số (overflow).

if int64(count) < size {
	fmt.Println("Đã sửa bằng ép kiểu int64")
}

Cách 2: Ép kiểu int64 sang int

Hãy thận trọng khi dùng cách này. Trên hệ thống 64-bit, int có độ rộng 64 bit, nhưng trên hệ thống 32-bit, nó chỉ có 32 bit. Nếu bạn ép kiểu một tệp int64 có dung lượng lớn (như 5 GB) sang int 32-bit, giá trị sẽ bị cắt ngắn. Điều này tạo ra các lỗi logic cực kỳ khó truy vết.

if count < int(size) {
	fmt.Println("Đã sửa bằng ép kiểu int")
}

Logic của hằng số

Bạn có thể nhận thấy rằng count < 100 vẫn biên dịch hoàn hảo ngay cả khi countint64. Điều này hoạt động vì các hằng số không định kiểu (untyped constants) trong Go có khả năng nhận biết ngữ cảnh. Chúng sẽ chấp nhận kiểu của biến mà chúng đang được so sánh cùng. Lỗi chỉ xảy ra khi cả hai vế của phép toán đã được cố định là các biến "có kiểu" (typed) cụ thể.

Xác minh

Để xác minh bản sửa lỗi, tôi đã cập nhật logic và chạy go run main.go. Nếu các kiểu dữ liệu khớp nhau, trình biên dịch sẽ không báo lỗi và chương trình sẽ thực thi. Tôi cũng đã thêm một bước kiểm tra phần trăm nhanh để đảm bảo phép toán số thực hoạt động như mong đợi.

// Mã cuối cùng đã xác minh
package main

import "fmt"

func main() {
	var processed int = 500
	var total int64 = 1024

	// Sử dụng ép kiểu tường minh cho các phép tính hỗn hợp
	percentage := float64(processed) / float64(total) * 100

	fmt.Printf("Tiến độ: %.2f%%\n", percentage)
	
	if int64(processed) != total {
		fmt.Println("Trạng thái: Chưa hoàn thành")
	}
}

Bài học kinh nghiệm

  • Chặt chẽ nghĩa là an toàn: Bằng cách buộc ép kiểu tường minh, Go ngăn chặn các lỗi tràn số âm thầm vốn thường gây đau đầu cho các lập trình viên C++ hoặc JavaScript.
  • Tiêu chuẩn hóa với int64: Khi xử lý kích thước tệp, ID cơ sở dữ liệu hoặc dấu thời gian, giờ đây tôi sử dụng int64 trên toàn bộ ứng dụng để giảm thiểu các lần ép kiểu gây phiền nhiễu.
  • Lưu ý kiểu trả về: Các hàm tiêu chuẩn như len() trả về int, nhưng os.FileInfo.Size() lại trả về int64. Việc ghi nhớ sự khác biệt này giúp ngăn chặn lỗi build ngay từ đầu.

Related Error Notes