最近開始學習GO語言,並做了一些編程練習。有道題要輸入帶空格的字符串,這在C/C++中很容易實現,但GO中好像並不那么容易。學過C/C++的可能都知道,在C中可以使用gets()函數,在C++可以使用getline()函數來實現輸入帶空格的字符串。那我們可能要問在GO中有沒有類似的函數?答案是否定的。
在GO中除了fmt和os包,我們還可以使用bufio來實現帶緩存輸入和輸出。
我們要怎樣讀取用戶從鍵盤(控制台)輸入的數據?輸入是指從鍵盤或其它標准輸入(os.Stdin)讀取數據。
使用fmt包里的Scan_或Sscan_系列函數輸入
package main
import "fmt"
var (
firstName, lastName string
str1, str2, str3 string
num int
str = "We / love / Go / 1314"
format = "%s / %s / %s / %d"
)
func main() {
fmt.Println("Please input your full name: ")
// 使用Scan輸入
fmt.Scan(&firstName, &lastName)
fmt.Printf("Hi %s %s!\n", firstName, lastName)
fmt.Println("Please again input your full name: ")
// 使用Scanln輸入
fmt.Scanln(&firstName, &lastName)
fmt.Printf("Hi %s %s!\n", firstName, lastName)
fmt.Println("Please again input your full name: ")
// 使用Scanf輸入
fmt.Scanf("%s %s", &firstName, &lastName)
fmt.Printf("Hi %s %s!\n", firstName, lastName)
fmt.Println("From the str we read: ")
// 使用Sscanf讀取
fmt.Sscanf(str, format, &str1, &str2, &str3, &num)
fmt.Println(str1, str2, str3, num)
}
若輸入為:
xiao hua
xiao ming
xiao hong
則輸出為:
Please input your full name:
xiao hua
Hi xiao hua!
Please again input your full name:
xiao ming
Hi xiao ming!
Please again input your full name:
xiao hong
Hi xiao hong!
From the str we read:
We love Go 1314
Scan()函數原型為:
func Scan(a ...interface{}) (n int, err error) {
return Fscan(os.Stdin, a...)
}
Scan從標准輸入掃描文本,將成功讀取的空白分隔的值保存進成功傳遞給本函數的參數。換行視為空白。返回成功掃描的條目個數和遇到的任何錯誤。如果讀取的條目比提供的參數少,會返回一個錯誤報告原因。
Scanln()函數原型為:
func Scanln(a ...interface{}) (n int, err error) {
return Fscanln(os.Stdin, a...)
}
Scanln類似於Scan,但會在換行符處停止掃描,在最后一個條目后必須有換行符或EOF。
Scanf()函數原型為:
func Scanf(format string, a ...interface{}) (n int, err error) {
return Fscanf(os.Stdin, format, a...)
}
Scanf從標准輸入掃描文本,根據format參數指定的格式將成功讀取的空白分隔的值保存進成功傳遞給本函數的參數。返回成功掃描的條目個數和遇到的任何錯誤。
輸入中的換行符必須與格式中的換行符匹配。
Sscanf()函數原型為:
func Sscanf(str string, format string, a ...interface{}) (n int, err error) {
return Fscanf((*stringReader)(&str), format, a...)
}
Sscanf從字符串str掃描文本,根據format參數指定的格式將成功讀取的空白分隔的值保存進成功傳遞給本函數的參數。返回成功掃描的條目個數和遇到的任何錯誤。
輸入中的換行符必須與格式中的換行符匹配。
Scan與Scanln方法的區別:
- Scan函數會識別空格左右的內容,哪怕換行符存在也不會影響Scan對內容的獲取。
- Scanln函數會識別空格左右的內容,但是一旦遇到換行符就會立即結束,不論后續還是否存在需要輸入的內容。
使用bufio包里帶緩沖的Reader實現帶空格字符串的輸入
package main
import (
"bufio"
"fmt"
"os"
)
//var inputReader *bufio.Reader
//var input string
//var err error
func main() {
inputReader := bufio.NewReader(os.Stdin) // 使用了自動類型推導,不需要var關鍵字聲明
//inputReader = bufio.NewReader(os.Stdin)
fmt.Println("Please input your name: ")
//input, err = inputReader.ReadString('\n')
input, err := inputReader.ReadString('\n')
if err == nil {
fmt.Printf("Your name is: %s\n", input)
}
}
若輸入為:
xiao hua
則輸出為:
Please input your name:
xiao hua
Your name is: xiao hua
上例中,inputReader是個指針,它指向一個bufio類的Reader,然后在main函數里,通過bufio.NewReader(os.Stdin)
創建了一個buffer Reader,並聯接到inputReader這個變量。
bufio.NewReader()函數原型為:
func NewReader(rd io.Reader) *Reader {
return NewReaderSize(rd, defaultBufSize)
}
任何符合io.Reader接口的對象法都可以作為bufio.NewReader()里的參數,並返回一個新的帶緩沖的io.Reader,os.Stdin符合這個條件。這個帶緩沖的Reader有一個方法ReadString(delim byte), 這個方法會一直讀數據,直到遇到了指定的終止符(delim byte)才結束輸入,終止符將成為輸入的一部分,一起放到buffer里。
RearString()函數原型為:
func (b *Reader) ReadString(delim byte) (string, error) {
bytes, err := b.ReadBytes(delim)
return string(bytes), err
}
ReadString返回值是讀到的字符串及nil。如果在讀到結束時沒有發現指定的結束符(delim byte),將返回一個 err != nil。在上面的例子中,我們從鍵盤輸入直到鍵入“\n”才結束。屏幕是標准輸出os.Stdout,錯誤信息被寫到os.Stderr。大多情況下,os.Stderr等同os.Stdout。
一般情況下,在GO的代碼里省略了變量聲明,而直接使用”:=“進行自動類型推導,如:
inputReader := bufio.NewReader(os.Stdin)
input, err := inputReader.ReadString('\n')
總結
GO中Scan_或Sscan_系列函數與C中的scan_系統函數的用法相似,學過C的人可以很快學會這些函數的使用。但要實現帶空格字符串的輸入,則要使用bufio包里帶緩沖的Reader和os包里的os.Stdin。
個人主頁: