Go輸入輸出
package main
import "fmt"
func main() {
fmt.Println("Hello 世界!")
}本站的第一個入門的案例就是輸出一個字符串,這一節就來講一下在 Go 中如何進行輸入輸出。
文件描述符
var (
Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
)在os包下有三個外暴露的文件描述符,其類型都是*os.File,分別是:
os.Stdin- 標准輸入os.Stdout- 標准輸出os.Stderr- 標准錯誤
Go 中的輸入輸出都離不開它們。
輸出
在 Go 中輸出有很多中方法,下面幾個比較常見的
stdout
因為標准輸出本身就是一個文件,所以你可以直接將字符串寫入到標准輸出中
package main
import "os"
func main() {
os.Stdout.WriteString("hello world!")
}print
Go 有兩個內置的函數print,println,他們會將參數輸出到標准錯誤中,僅做調試用,一般不推薦使用。
package main
func main() {
print("hello world!\n")
println("hello world")
}fmt
最常見的用法是使用fmt包,它提供了fmt.Println函數,該函數默認會將參數輸出到標准輸出中。
package main
import "fmt"
func main() {
fmt.Println("hello world!")
}它的參數支持任意類型,如果類型實現了String接口也會調用String方法來獲取其字符串表現形式,所以它輸出的內容可讀性比較高,適用於大部分情況,不過由於內部用到了反射,在性能敏感的場景不建議大量使用。
bufio
bufio提供了可緩沖的輸出方法,它會先將數據寫入到內存中,積累到了一定閾值再輸出到指定的Writer中,默認緩沖區大小是4KB。在文件 IO,網絡 IO 的時候建議使用這個包。
func main() {
writer := bufio.NewWriter(os.Stdout)
defer writer.Flush()
writer.WriteString("hello world!")
}你也可以把它和fmt包結合起來用
func main() {
writer := bufio.NewWriter(os.Stdout)
defer writer.Flush()
fmt.Fprintln(writer, "hello world!")
}格式化
Go 中的格式化輸出功能基本上由fmt.Printf函數提供,如果你學過 C 系語言,一定會覺得很熟悉,下面是一個簡單的例子。
func main() {
fmt.Printf("hello world, %s!", "jack")
}下面是 Go 目前所有的格式化動詞。
| 0 | 格式化 | 描述 | 接收類型 |
|---|---|---|---|
| 1 | %% | 輸出百分號% | 任意 |
| 2 | %s | 輸出string/[] byte值 | string,[] byte |
| 3 | %q | 格式化字符串,輸出的字符串兩端有雙引號"" | string,[] byte |
| 4 | %d | 輸出十進制整型值 | 整型 |
| 5 | %f | 輸出浮點數 | 浮點 |
| 6 | %e | 輸出科學計數法形式 ,也可以用於復數 | 浮點 |
| 7 | %E | 與%e相同 | 浮點 |
| 8 | %g | 根據實際情況判斷輸出%f或者%e,會去掉多余的 0 | 浮點 |
| 9 | %b | 輸出整型的二進制表現形式 | 數字 |
| 10 | %#b | 輸出二進制完整的表現形式 | 數字 |
| 11 | %o | 輸出整型的八進制表示 | 整型 |
| 12 | %#o | 輸出整型的完整八進制表示 | 整型 |
| 13 | %x | 輸出整型的小寫十六進制表示 | 數字 |
| 14 | %#x | 輸出整型的完整小寫十六進制表示 | 數字 |
| 15 | %X | 輸出整型的大寫十六進制表示 | 數字 |
| 16 | %#X | 輸出整型的完整大寫十六進制表示 | 數字 |
| 17 | %v | 輸出值原本的形式,多用於數據結構的輸出 | 任意 |
| 18 | %+v | 輸出結構體時將加上字段名 | 任意 |
| 19 | %#v | 輸出完整 Go 語法格式的值 | 任意 |
| 20 | %t | 輸出布爾值 | 布爾 |
| 21 | %T | 輸出值對應的 Go 語言類型值 | 任意 |
| 22 | %c | 輸出 Unicode 碼對應的字符 | int32 |
| 23 | %U | 輸出字符對應的 Unicode 碼 | rune,byte |
| 24 | %p | 輸出指針所指向的地址 | 指針 |
使用fmt.Sprintf或者fmt.Printf來格式化字符串或者輸出格式化字符串,看幾個例子
fmt.Printf("%%%s\n", "hello world")
fmt.Printf("%s\n", "hello world")
fmt.Printf("%q\n", "hello world")
fmt.Printf("%d\n", 2<<7-1)
fmt.Printf("%f\n", 1e2)
fmt.Printf("%e\n", 1e2)
fmt.Printf("%E\n", 1e2)
fmt.Printf("%g\n", 1e2)
fmt.Printf("%b\n", 2<<7-1)
fmt.Printf("%#b\n", 2<<7-1)
fmt.Printf("%o\n", 2<<7-1)
fmt.Printf("%#o\n", 2<<7-1)
fmt.Printf("%x\n", 2<<7-1)
fmt.Printf("%#x\n", 2<<7-1)
fmt.Printf("%X\n", 2<<7-1)
fmt.Printf("%#X\n", 2<<7-1)
type person struct {
name string
age int
address string
}
fmt.Printf("%v\n", person{"lihua", 22, "beijing"})
fmt.Printf("%+v\n", person{"lihua", 22, "beijing"})
fmt.Printf("%#v\n", person{"lihua", 22, "beijing"})
fmt.Printf("%t\n", true)
fmt.Printf("%T\n", person{})
fmt.Printf("%c%c\n", 20050, 20051)
fmt.Printf("%U\n", '碼')
fmt.Printf("%p\n", &person{})使用其它進制時,在%與格式化動詞之間加上一個空格便可以達到分隔符的效果,例如
func main() {
str := "abcdefg"
fmt.Printf("%x\n", str)
fmt.Printf("% x\n", str)
}該例輸出的結果為
61626364656667
61 62 63 64 65 66 67在使用數字時,還可以自動補零。比如
fmt.Printf("%09d", 1)
// 000000001二進制同理
fmt.Printf("%09b", 1<<3)
// 000001000錯誤情況
格式化字符數量 < 參數列表數量
fmt.Printf("", "") //%!(EXTRA string=)格式化字符數量 > 參數列表數量
fmt.Printf("%s%s", "") //%!s(MISSING)類型不匹配
fmt.Printf("%s", 1) //%!s(int=1)缺少格式化動詞
fmt.Printf("%", 1) // %!(NOVERB)%!(EXTRA int=1)輸入
下面介紹常見的輸入方法
read
你可以像直接讀文件一樣,讀取輸入內容,如下
func main() {
var buf [1024]byte
n, _ := os.Stdin.Read(buf[:])
os.Stdout.Write(buf[:n])
}這樣用起來太麻煩了,一般不推薦使用。
fmt
我們可以使用fmt包提供的幾個函數,用起來跟 C 差不多。
// 掃描從os.Stdin讀入的文本,根據空格分隔,換行也被當作空格
func Scan(a ...any) (n int, err error)
// 與Scan類似,但是遇到換行停止掃描
func Scanln(a ...any) (n int, err error)
// 根據格式化的字符串掃描
func Scanf(format string, a ...any) (n int, err error)讀取兩個數字
func main() {
var a, b int
fmt.Scanln(&a, &b)
fmt.Printf("%d + %d = %d\n", a, b, a+b)
}讀取固定長度的數組
func main() {
n := 10
s := make([]int, n)
for i := range n {
fmt.Scan(&s[i])
}
fmt.Println(s)
}1 2 3 4 5 6 7 8 9 10
[1 2 3 4 5 6 7 8 9 10]bufio
在有大量輸入需要讀取的時候,就建議使用bufio.Reader來進行內容讀取
func main() {
reader := bufio.NewReader(os.Stdin)
var a, b int
fmt.Fscanln(reader, &a, &b)
fmt.Printf("%d + %d = %d\n", a, b, a+b)
}scanner
bufio.Scanner與bufio.Reader類似,不過它是按行讀取的。
func main() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
line := scanner.Text()
if line == "exit" {
break
}
fmt.Println("scan", line)
}
}結果如下
first line
scan first line
second line
scan second line
third line
scan third line
exitTIP
在輸入輸出這方面,想要練手的話,去洛谷做幾道簡單的 ACM 模式算法題就能上手熟悉了。
