[pkg] fmt
- Package fmt @ Golang
- fmt.Printf formatting tutorial and cheat sheet @ YourBasic
TL;DR
Print
、Println
、Printf
都會直接輸出內容Sprint
、Sprintln
、Sprintf
則可以把要輸出的內容儲存成變數
fmt.Printf("%T", "型別")
fs += fmt.Sprintf("%-25v ...$%0.2f", "total:", total)
// Format Specifier
// %T,型別
// %v,預設的格式
// %-25v,輸出的內容會佔據 25 個位元的長度
// %+v,印出 struct 時,會多欄位名稱
// %#v,印出 struct 時,會多 struct 名稱與欄位名稱
// %t,boolean
// %s,字串
// %p,記憶體位置(pointer)
// %q,在變數前後加上引號
// 數值
// %d
// %0.2f,取到小數第二位的浮點數
印出訊息:
// 印出訊息
// 不會自動換行,“," 之間也不會有空格"
fmt.Print("Hello", "Go") // HelloGo
// 自動換行,且 "," 之間會加上空格
fmt.Println("Hello", "Go") // Hello Go
fmt.Println("My age is", age, "and my name is", name)
// Print with Formatted Strings
fmt.Printf("Hello %s", "Go") // Hello Go
fmt.Printf("My age is %d and my name is %q\n", age, name)
// 如果希望控制換行,可以用 "`"(backtick)
fmt.Print(`
Hello,
世
界
`)
字串:
// Saved Formatted Strings
formErrMsg := fmt.Sprintf("get form err: %s", err.Error())
數值:
fmt.Printf("The price is %0.2f\n", 1.9932123) // 1.99
Slices:
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
記憶體位置:
slice := []string{"a", "a"}
fmt.Printf("%p", &slice)
格式
// %v,印出預設的格式
// %+v,印出 struct 時,會多欄位名稱
// %s,印出字串
fmt.Printf("Hello %s", "Go") // Hello Go
// %T,印出變數的型別
fmt.Printf("v is of type %T\n", v)
// %g,印出 float64
var v float64 = 10
var lim float64 = 5
fmt.Printf("%g >= %g\n", v, lim)
Functions
Scan, Scanln
官方文件
可以從 Terminal 取得使用者輸入的內容(但使用者則只能輸入一行,不能多行):
// 取得使用者輸入的投資金額
func main() {
var age int
var height int
var weight int
fmt.Print("Enter your name and age: ")
// 取得使用者輸入的內容
fmt.Scan(&age, &height, &weight)
fmt.Printf("Age: %d, Height: %d, Weight: %d\n", age, height, weight)
}
Scan(s)
:輸入的內容會以「空格」當作分隔,可以在 Termianl 中換行,換行會被當成 spaceScanln(s)
:輸入的內容會以「空格」當作分隔,一旦遇到換行即停止,因此不能以換行的方式輸入內容
Sprintf
在 6 Tips for Using Strings in Go 中建議盡可能不要使用這個方法,最好只有在需要建立帶有嵌入值的字串時使用,因為 fmt.Sprintf
並不會進行任何的型 別檢查,因此除非實際執行程式碼,不然很難找到錯誤。
如果是需要針對其他型別轉換成字串的話,建議使用 strconv
這個 package。
FPrint(w io.Writer, a) (n int, err error)
使用預設的 formats 將內容寫到 w
中:
func main() {
name := "Aaron"
age := 32
w := os.Stdout
if _, err := fmt.Fprint(w, "Hello ", name, " you are ", age, " years old"); err != nil {
fmt.Println(err)
}
}
輸出內容:
Hello Aaron you are 32 years old
Fscan(r, a)
掃描 r
中的內容,並以空格分隔後(換行也算空格),保存到對應的型別中(&i, &b, &s
):
func main() {
var (
i int
b bool
s string
)
r := strings.NewReader("5 true gophers")
fmt.Fscan(r, &i, &b, &s)
fmt.Println(i, b, s) // 5 true gophers
}
Fscanf(r, format, a)
掃描 r
中文字內容,根據定義的型別(%d %t %s
)將 r 中的值取出後,保存到對應型別的變數中(&i, &b, &s
):
// https://pkg.go.dev/fmt?tab=doc#Fscanf
func main() {
var (
i int
b bool
s string
)
r := strings.NewReader("5 true gophers")
fmt.Fscanf(r, "%d %t %s", &i, &b, &s)
fmt.Println(i, b, s) // 5 true gophers
}
Fscanln(r, a)
Fscanln
和 Fscan
非常類似,差別只在於 Fscanln
呼叫一次只會讀一行,在呼叫一次才會讀下一行,直到 EOF
func main() {
var (
s string
i int
c float64
)
text := `dmr 1771 1.61803398875
ken 271828 3.14159`
r := strings.NewReader(text)
for {
_, err := fmt.Fscanln(r, &s, &i, &c)
if err == io.EOF {
fmt.Println("EOF")
break
}
if err != nil {
if err.Error() == "unexpected newline" {
fmt.Println("unexpected newline")
break
}
panic(err)
}
fmt.Println(s, i, c)
}
}
輸出:
dmr 1771 1.61803398875
ken 271828 3.14159
EOF
其他
fmt 和 log 的差別
When to use log over fmt for debugging and printing error? @ StackOverflow