若要輸出訊息至主控台,可以透過 fmt 的 Print、Println、Printf 等函式,如果要從主控台讀取使用者輸入,可以透過 fmt 的 Scanf、Scanln 等函式。例如:
package main
import "fmt"
func main() {
    fmt.Print("輸入名稱 年齡:")
    var name string
    var age int
    fmt.Scanf("%s %d", &name, &age)
    fmt.Printf("嗨!%s!今年 %d 歲了啊?", name, age)
}
%s、%d 是格式符號,在 Go 中稱為 verb,Go 可用的 verb 可以在 fmt 套件的文件中找到。
Scanf 就類似 C 語言中的 scanf,可以格式化地取得輸入,底下是個範例:
輸入名稱 年齡:Justin 45
嗨!Justin!今年 45 歲了啊?
在按下 Enter 鍵後,實際上還有個 CR(carriage return)字元還未掃描,如果只是要取得空白分隔的輸入,並以換行作為結束,可以使用 Scanln:
package main
import "fmt"
func main() {
    fmt.Print("輸入空白分隔的文字")
    var text1, text2 string
    fmt.Scanln(&text1, &text2)
    fmt.Println(text1)
    fmt.Println(text2)
}
如果是 Scan 的話,也是掃描以空白區隔的輸入,按下 Enter 鍵的 CR 字元,也會被視為空白。
Println、Printf 會使用標準輸出(Standout),如果想使用標準錯誤(Standard err)呢?可以透過  Fprint、Fprintln、Fprintf 等函式,第一個引數指定 os.Stderr。例如:
package main
import (
    "fmt"
    "os"
)
func main() {
    fmt.Fprintln(os.Stderr, "輸出至標準錯誤")
}
os 套件的 Stderr 代表標準錯誤,而 Stdin、Stdout 代表標準輸入與輸出,它們的型態是 *os.File,若願意的話,也可以直接操作它們,例如 File 定義了 Read 與 Write 方法,可以指定一個型態為 byte[] 的 slice,Read 會讀入同樣長度的資料至 slice,後者可以將同等長度的資料輸出。例如:
package main
import "os"
func main() {
    buf := make([]byte, 5);
    os.Stdout.Write([]byte("輸入五個數字:"))
    os.Stdin.Read(buf)
    os.Stdout.Write(buf)
}   
實際上,os.File 可用的方法不只有 Read、Write,先留意這兩個方法的目的在於,這兩個方法分別符合 io.Reader、io.Writer 定義的行為:
type Reader interface {
    Read(p []byte) (n int, err error)
}
type Writer interface {
    Write(p []byte) (n int, err error)
}
如果察看 fmt 的 Fprint、Fprintln、Fprintf 等函式,可以發現它們第一個參數宣告的型態並不是 *os.File,而是 io.Writer:
func Fprint(w io.Writer, a ...interface{}) (n int, err error)
func Fprintln(w io.Writer, a ...interface{}) (n int, err error)
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)
類似地,Fscan 字樣開頭的幾個函式,第一個參數接受的是 io.Reader:
func Fscan(r io.Reader, a ...interface{}) (n int, err error)
func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error)
func Fscanln(r io.Reader, a ...interface{}) (n int, err error)
這表示,fmt 套件中這些函式,並不只能用於標準輸入、輸出或錯誤,例如,strings.NewReader 函式,可以指定字串,傳回 *Reader,這表示 fmt 的 Fscanf 等函式,可以從字串讀取輸入。例如:
package main
import (
    "fmt"
    "io"
    "strings"
)
func main() {
    data := `Justin 45
             Monica 42
             Irene 12`
    r := strings.NewReader(data)
    var name string
    var age int
    for {
        if _, err := fmt.Fscanln(r, &name, &age); err == io.EOF {
            break
        }
        fmt.Printf("%s: %d\n", name, age)
    }
}  
Fscanln 會傳回掃描的筆數,如果筆數少於指定的掃描數量,err 會指出原因,在檔案讀取結束(End of file)時,err 會是 io.EOF,在上例中,資料來源是個格式確定的字串,因此僅簡單地判斷 err 是否為 io.EOF 來結束掃描。
os.File 不過是具有 io.Reader、io.Writer 的行為罷了,os.File 代表檔案,也就是說 Fprint、Fprintln、Fprintf、Fscan、Fscanln、Fscanf 等函式,也可以用在檔案讀寫,其實標準輸入、輸出、錯誤等,也是被視為檔案的,這在 os 的 file.go 可以看到:
var (
    Stdin  = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
    Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
    Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
)
因此 IO 之類的操作,在 Go 中非常靈活,一切都看 API 上可接受行為而定,不受型態之限制,這之後再從實際的例子中來談。

