跳至主要内容

[pkg] fmt

TL;DR

  • PrintPrintlnPrintf 都會直接輸出內容
  • SprintSprintlnSprintf 則可以把要輸出的內容儲存成變數
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 中換行,換行會被當成 space
  • Scanln(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)

FscanlnFscan 非常類似,差別只在於 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