Hướng dẫn sử dụng fmt.Printf trong ngôn ngữ Go

Chuỗi định dạng và các tham số

Các hàm thuộc họ *printf đều hỗ trợ tham số định dạng format, ở đây chúng ta sẽ phân loại theo từng placeholder để dễ dàng tra cứu và ghi nhớ.

Placeholder chung

Placeholder Mô tả
%v Biểu diễn mặc định của giá trị
%+v Tương tự %v nhưng khi in cấu trúc (struct) sẽ thêm tên trường
%#v Biểu diễn cú pháp Go của giá trị
%T In kiểu dữ liệu của giá trị
%% Ký hiệu phần trăm

Ví dụ mã nguồn:

package main

import "fmt"

func main() {
    fmt.Printf("%v\n", 100)
    fmt.Printf("%v\n", true)
    o := struct{ ten string }{"Ngôi Sao Nhỏ"}
    fmt.Printf("%v\n", o)
    fmt.Printf("%#v\n", o)
    fmt.Printf("%T\n", o)
    fmt.Printf("100%%\n")
}

Kết quả đầu ra:

100
true
{Ngôi Sao Nhỏ}
struct { ten string }{ten:"Ngôi Sao Nhỏ"}
struct { ten string }
100%

Kiểu Boolean

Placeholder Mô tả
%t true hoặc false

Kiểu Số Nguyên

Placeholder Mô tả
%b Biểu diễn dưới dạng nhị phân
%c Giá trị tương ứng với ký tự Unicode
%d Biểu diễn dưới dạng thập phân
%o Biểu diễn dưới dạng bát phân
%x Biểu diễn dưới dạng thập lục phân (chữ cái a-f)
%X Biểu diễn dưới dạng thập lục phân (chữ cái A-F)
%U Biểu diễn dưới dạng Unicode: U+1234
%q Biểu diễn dưới dạng ký tự đơn với dấu ngoặc đơn, nếu cần sẽ có escape sequence an toàn
package main

import "fmt"

func main() {
    so := 65
    fmt.Printf("%b\n", so)
    fmt.Printf("%c\n", so)
    fmt.Printf("%d\n", so)
    fmt.Printf("%o\n", so)
    fmt.Printf("%x\n", so)
    fmt.Printf("%X\n", so)
}

Kết quả đầu ra:

1000001
A
65
101
41
41

Số Thực và Số Phức

Placeholder Mô tả
%b Định dạng khoa học không phần thập phân, chỉ số mũ nhị phân, ví dụ -123456p-78
%e Định dạng khoa học, ví dụ -1234.456e+78
%E Định dạng khoa học, ví dụ -1234.456E+78
%f Có phần thập phân nhưng không có số mũ, ví dụ 123.456
%F Tương đương với %f
%g Chọn giữa %e hoặc %f tùy vào độ chính xác và gọn hơn
%G Chọn giữa %E hoặc %F tùy vào độ chính xác và gọn hơn
package main

import "fmt"

func main() {
    f := 12.34
    fmt.Printf("%b\n", f)
    fmt.Printf("%e\n", f)
    fmt.Printf("%E\n", f)
    fmt.Printf("%f\n", f)
    fmt.Printf("%g\n", f)
    fmt.Printf("%G\n", f)
}

Kết quả đầu ra:

6946802425218990p-49
1.234000e+01
1.234000E+01
12.340000
12.34
12.34

Chuỗi và []byte

Placeholder Mô tả
%s In trực tiếp chuỗi hoặc []byte
%q Biểu diễn dưới dạng chuỗi với dấu ngoặc kép, nếu cần sẽ có escape sequence an toàn
%x Mỗi byte được biểu diễn bằng hai ký tự thập lục phân (chữ cái a-f)
%X Mỗi byte được biểu diễn bằng hai ký tự thập lục phân (chữ cái A-F)
package main

import "fmt"

func main() {
    s := "Ngôi Sao Nhỏ"
    fmt.Printf("%s\n", s)
    fmt.Printf("%q\n", s)
    fmt.Printf("%x\n", s)
    fmt.Printf("%X\n", s)
}

Kết quả đầu ra:

Ngôi Sao Nhỏ
"Ngôi Sao Nhỏ"
e5b08fe78e8be5ad90
E5B08FE78E8BE5AD90

Con Trỏ

Placeholder Mô tả
%p Biểu diễn dưới dạng thập lục phân kèm tiền tố 0x
package main

import "fmt"

func main() {
    a := 10
    fmt.Printf("%p\n", &a)
    fmt.Printf("%#p\n", &a)
}

Kết quả đầu ra:

0xc000094000
c000094000

Biểu thức Chiều Rộng

Chiều rộng được chỉ định bởi một số thập phân ngay sau dấu %. Nếu không chỉ định chiều rộng, giá trị sẽ được biểu diễn mà không có bất kỳ khoảng trống nào bổ sung. Độ chính xác được chỉ định bởi số thập phân sau dấu chấm. Nếu không chỉ định độ chính xác, giá trị mặc định sẽ được sử dụng; nếu dấu chấm không đi kèm số thì độ chính xác là 0.

package main

import "fmt"

func main() {
    n := 12.34
    fmt.Printf("%f\n", n)
    fmt.Printf("%9f\n", n)
    fmt.Printf("%.2f\n", n)
    fmt.Printf("%9.2f\n", n)
    fmt.Printf("%9.f\n", n)
}

Kết quả đầu ra:

12.340000
12.340000
12.34
    12.34
       12

Các Flag Khác

Placeholder Mô tả
’+’ Lúc nào cũng hiển thị dấu dương hoặc âm của số; đối với %q (%+q), nó tạo ra một chuỗi hoàn toàn gồm các ký tự ASCII (bằng cách thoát).
’ ‘ Đối với số, thêm dấu cách trước số dương và dấu trừ trước số âm; đối với chuỗi khi dùng %x hoặc %X (% x hoặc % X), mỗi byte được in ra sẽ có dấu cách giữa chúng.
’-’ Thêm khoảng trắng bên phải thay vì bên trái (chuyển từ căn lề phải sang căn lề trái).
’#’ Thực hiện thêm tiền tố 0 cho số bát phân (%#o), tiền tố 0x cho số thập lục phân (%#x) hoặc 0X cho số thập lục phân viết hoa (%#X); bỏ tiền tố 0x đối với con trỏ (%#p).
‘0’ Sử dụng số 0 thay vì khoảng trắng để điền vào, đối với kiểu số, số 0 sẽ được đặt sau dấu cộng hoặc trừ.
package main

import "fmt"

func main() {
    s := "Ngôi Sao Nhỏ"
    fmt.Printf("%s\n", s)
    fmt.Printf("%5s\n", s)
    fmt.Printf("%-5s\n", s)
    fmt.Printf("%5.7s\n", s)
    fmt.Printf("%-5.7s\n", s)
    fmt.Printf("%5.2s\n", s)
    fmt.Printf("%05s\n", s)
}

Kết quả đầu ra:

Ngôi Sao Nhỏ
  Ngôi Sao Nhỏ
Ngôi Sao Nhỏ  
  Ngôi Sao Nhỏ
Ngôi Sao Nhỏ  
   Ngôi Sa
00Ngôi Sao Nhỏ

Nhập Dữ Liệu

Trong gói fmt của Go, có ba hàm fmt.Scan, fmt.Scanf, và fmt.Scanln giúp lấy dữ liệu từ người dùng trong quá trình chạy chương trình.

fmt.Scan

Hàm định nghĩa như sau:

func Scan(a ...interface{}) (n int, err error)
  • Scan quét văn bản từ đầu vào chuẩn, đọc các giá trị được phân tách bởi khoảng trắng và lưu vào các tham số truyền vào.
  • Hàm trả về số lượng dữ liệu đã quét thành công và lỗi nếu có.

Ví dụ mã nguồn:

package main

import "fmt"

func main() {
    var (
        ten     string
        tuoi    int
        ketHon bool
    )
    fmt.Scan(&ten, &tuoi, &ketHon)
    fmt.Printf("Kết quả quét ten:%s tuoi:%d ketHon:%t \n", ten, tuoi, ketHon)
}

Chạy đoạn mã trên trong terminal và nhập lần lượt Ngôi Sao Nhỏ, 28, false với dấu cách làm phân cách.

$ ./scan_demo 
Ngôi Sao Nhỏ 28 false
Kết quả quét ten:Ngôi Sao Nhỏ tuoi:28 ketHon:false 

fmt.Scan quét dữ liệu từ đầu vào chuẩn và lưu các giá trị được phân tách bởi khoảng trắng vào các tham số được chỉ định.

fmt.Scanf

Hàm định nghĩa như sau:

func Scanf(format string, a ...interface{}) (n int, err error)
  • Scanf quét văn bản từ đầu vào chuẩn, đọc các giá trị dựa trên định dạng được chỉ định và lưu vào các tham số truyền vào.
  • Hàm trả về số lượng dữ liệu đã quét thành công và lỗi nếu có.

Ví dụ mã nguồn:

package main

import "fmt"

func main() {
    var (
        ten     string
        tuoi    int
        ketHon bool
    )
    fmt.Scanf("1:%s 2:%d 3:%t", &ten, &tuoi, &ketHon)
    fmt.Printf("Kết quả quét ten:%s tuoi:%d ketHon:%t \n", ten, tuoi, ketHon)
}

Chạy đoạn mã trên trong terminal và nhập theo đúng định dạng được yêu cầu.

$ ./scan_demo 
1:Ngôi Sao Nhỏ 2:28 3:false
Kết quả quét ten:Ngôi Sao Nhỏ tuoi:28 ketHon:false 

fmt.Scanf khác với fmt.Scan ở chỗ nó yêu cầu dữ liệu phải tuân theo định dạng cụ thể được chỉ định.

fmt.Scanln

Hàm định nghĩa như sau:

func Scanln(a ...interface{}) (n int, err error)
  • Scanln hoạt động tương tự Scan nhưng chỉ dừng quét khi gặp dòng mới.
  • Hàm trả về số lượng dữ liệu đã quét thành công và lỗi nếu có.

Ví dụ mã nguồn:

package main

import "fmt"

func main() {
    var (
        ten     string
        tuoi    int
        ketHon bool
    )
    fmt.Scanln(&ten, &tuoi, &ketHon)
    fmt.Printf("Kết quả quét ten:%s tuoi:%d ketHon:%t \n", ten, tuoi, ketHon)
}

Chạy đoạn mã trên trong terminal và nhập lần lượt Ngôi Sao Nhỏ, 28, false với dấu cách làm phân cách.

$ ./scan_demo 
Ngôi Sao Nhỏ 28 false
Kết quả quét ten:Ngôi Sao Nhỏ tuoi:28 ketHon:false 

fmt.Scanln dừng quét khi gặp dòng mới.

bufio.NewReader

Khi bạn muốn nhận toàn bộ nội dung đầu vào, kể cả khi nó chứa dấu cách, bạn có thể sử dụng gói bufio. Ví dụ mã nguồn:

package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
)

func main() {
    reader := bufio.NewReader(os.Stdin) // Tạo đối tượng đọc từ đầu vào chuẩn
    fmt.Print("Nhập nội dung:")
    text, _ := reader.ReadString('\n') // Đọc đến khi gặp dòng mới
    text = strings.TrimSpace(text)
    fmt.Printf("%#v\n", text)
}

Fscan Series

Các hàm này tương tự như fmt.Scan, fmt.Scanf, và fmt.Scanln, nhưng thay vì đọc từ đầu vào chuẩn, chúng đọc từ io.Reader.

func Fscan(r io.Reader, a ...interface{}) (n int, err error)
func Fscanln(r io.Reader, a ...interface{}) (n int, err error)
func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error)

Sscan Series

Các hàm này tương tự như fmt.Scan, fmt.Scanf, và fmt.Scanln, nhưng thay vì đọc từ đầu vào chuẩn, chúng đọc từ chuỗi được chỉ định.

func Sscan(str string, a ...interface{}) (n int, err error)
func Sscanln(str string, a ...interface{}) (n int, err error)
func Sscanf(str string, format string, a ...interface{}) (n int, err error)

Thẻ: Go fmt printf

Đăng vào ngày 17 tháng 6 lúc 04:07