Go Zero to Hero - Bài 9: Package fmt - In định dạng và nhập dữ liệu từ console
Package fmt chia làm hai nhóm nhiệm vụ chính: Output (In dữ liệu ra/Định dạng chuỗi) và Input (Đọc dữ liệu vào).
1. Xuất dữ liệu (Output): Bộ 3 quyền lực Print, Println, Printf
fmt.Print và fmt.Println
Hai hàm này rất đơn giản:
Print: In các giá trị ra màn hình, nối liền nhau.Println: GiốngPrintnhưng tự động chèn thêm một khoảng trắng giữa các biến và tự động xuống dòng ở cuối.
name := "Hoàng"
age := 21
fmt.Print("Tên:", name, "Tuổi:", age) // Kết quả: Tên:HoàngTuổi:21
fmt.Println("Tên:", name, "Tuổi:", age) // Kết quả: Tên: Hoàng Tuổi: 21 (và xuống dòng)
fmt.Printf (Print Format): Nghệ thuật định dạng
Đây mới là "trùm cuối". Khi làm Backend, bạn sẽ thường xuyên phải log ra những dòng thông báo kết hợp giữa chuỗi tĩnh và giá trị biến. Nếu dùng Println nối chuỗi bằng dấu phẩy thì code trông rất xấu.
Printf cho phép bạn tạo một chuỗi mẫu (template) với các "chỗ trống" (gọi là verbs hoặc format specifiers), sau đó điền các biến vào những chỗ trống đó.
name := "Hoàng"
role := "Backend Developer"
salary := 2500.50
// Sử dụng Printf để định dạng
fmt.Printf("Xin chào %s! Chức vụ của bạn là %s. Lương: %.2f USD\n", name, role, salary)
Bảng cẩm nang các Verbs (Chỉ mục định dạng) cần nhớ nhất:
| Verb | Ý nghĩa | Ví dụ thực tế |
|---|---|---|
%s |
Dành cho Chuỗi (String) | fmt.Printf("%s", "Hello") |
%d |
Dành cho Số nguyên (Decimal/Integer) | fmt.Printf("%d", 100) |
%f |
Dành cho Số thực. Bạn có thể ép số thập phân bằng %.2f (lấy 2 số lẻ) |
fmt.Printf("%.2f", 3.1415) |
%T |
Siêu hữu ích: In ra Kiểu dữ liệu của biến | fmt.Printf("%T", age) -> int |
%v |
(Value) In ra giá trị mặc định của biến, bất kể kiểu gì | fmt.Printf("%v", name) |
Tuyệt chiêu Debug Struct cho Backend Dev: Sau này khi bạn học đến
Struct(để hứng dữ liệu JSON, DB record), việc log ra xem bên trong struct chứa gì là bắt buộc. Hãy nhớ hai verb này:
%+v: In ra giá trị kèm theo tên field (tên trường dữ liệu).%#v: In ra giá trị giống hệt cú pháp code Go (rất chi tiết).
2. fmt.Sprintf: Trả về chuỗi thay vì in ra màn hình
Đôi khi, bạn không muốn in thông báo ra màn hình Console, mà bạn muốn lưu thông báo đó vào một biến chuỗi để chèn vào database, gửi qua API response, hay ghi vào file log.
Hàm Sprintf (String Print Format) sinh ra để làm việc này. Nó dùng chung quy tắc verbs (%s, %d...) với Printf, chỉ khác là nó return (trả về) một chuỗi.
func main() {
orderID := 1024
status := "PAID"
// Tạo câu thông báo và lưu vào biến
logMsg := fmt.Sprintf("Đơn hàng #%d đã chuyển sang trạng thái %s", orderID, status)
// Lúc này logMsg là một chuỗi, bạn có thể gửi lên Telegram, lưu DB...
// fmt.Println(logMsg)
}
3. Nhập dữ liệu (Input) với fmt.Scan
Để tạo một ứng dụng CLI (Command Line Interface) có tính tương tác, chúng ta cần đọc dữ liệu người dùng nhập vào từ bàn phím. fmt cung cấp hàm Scan, Scanln và Scanf.
Một sự đụng độ sớm với Con Trỏ (Pointer):
Để hàm Scan có thể thay đổi giá trị của một biến sau khi bạn nhập từ bàn phím, bạn phải truyền địa chỉ bộ nhớ của biến đó vào hàm, bằng cách đặt dấu & trước tên biến.
package main
import "fmt"
func main() {
var name string
var age int
fmt.Print("Vui lòng nhập tên và tuổi của bạn (cách nhau bởi dấu cách): ")
// Truyền địa chỉ của name (&name) và age (&age)
fmt.Scan(&name, &age)
fmt.Printf("Xác nhận: Tên bạn là %s, %d tuổi.\n", name, age)
}
Hạn chế chết người của fmt.Scan:
Hàm fmt.Scan sử dụng dấu cách (Space) hoặc dấu xuống dòng (Enter) để phân tách các biến.
Điều này có nghĩa là nếu bạn yêu cầu người dùng nhập họ tên đầy đủ, ví dụ: Nguyễn Huy Hoàng, hàm Scan sẽ tưởng "Nguyễn" là một biến, "Huy" là biến thứ hai.
Giải pháp thay thế cho việc nhập chuỗi dài:
Khi làm việc thực tế, để nhập một chuỗi có chứa dấu cách (đọc hết một dòng), các Gopher không dùng fmt.Scan, mà dùng package bufio (Buffered I/O) kết hợp với os.Stdin:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
// Khởi tạo một reader đọc dữ liệu từ Standard Input (bàn phím)
reader := bufio.NewReader(os.Stdin)
fmt.Print("Nhập họ tên đầy đủ của bạn: ")
// Đọc cho đến khi gặp ký tự xuống dòng (\n)
fullName, _ := reader.ReadString('\n')
fmt.Printf("Xin chào %s", fullName)
}
Tổng kết
Tóm gọn "công lực" của fmt:
- Output Console: Dùng
Printlnđể in nhanh, dùngPrintfđể định dạng chuyên nghiệp với các verbs (%s,%d,%+v). - String Formatting: Dùng
Sprintfđể "nặn" ra một chuỗi chuẩn chỉnh và lưu vào biến phục vụ cho API hay Logging. - Input Console: Dùng
Scancho việc đọc các biến đơn lẻ (không chứa dấu cách). Dùngbufiokhi cần đọc một dòng dài (có chứa dấu cách).
All rights reserved