目錄
- 為什麼專講標準庫?
- io.Reader 與 io.Writer
- encoding/json
- net/http 客戶端
- net/http 伺服器
- time 套件
- strings 與 strconv
- os 與 os/exec
- 實戰範例
- 最佳實踐
- 常見問題
- 總結
- 參考資源
為什麼專講標準庫?
Go 的標準庫夠用且穩定,新人最大誤區是先找第三方套件。掌握以下七大套件後,多數 Web 服務 / CLI 工具可以完全用 stdlib 寫:
io— 串流的抽象(Reader/Writer)encoding/json— JSON 編解碼net/http— HTTP client + servertime— 時間處理strings/strconv— 字串操作與型別轉換os/os/exec— 檔案系統與子行程
核心特點
- 🎯 無外部依賴:減少 go.mod 雜訊與版本衝突
- ⚡ 穩定的 API:標準庫向下相容承諾(Go 1.x 不會 breaking change)
- 🔧 效能穩:標準庫經過大量真實流量驗證
- 📦 整合深:跨套件直接共用(如
net/http內部用io.Reader)
io.Reader 與 io.Writer
io.Reader / io.Writer 是 Go 的串流通用介面,標準庫所有 I/O 都建在這兩個介面上。
介面定義
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
任何能讀寫位元組的東西都實作這兩個介面:
*os.File*bytes.Buffer*strings.Reader*http.Response.Bodynet.Conn
常見組合
從 reader 讀全部 bytes
import "io"
data, err := io.ReadAll(reader) // 注意:對未知大小謹慎用
從 reader 拷貝到 writer
n, err := io.Copy(dst, src) // 串流拷貝,記憶體不爆
用 buffer 包裝小資料
import (
"bytes"
"strings"
)
// string 當 reader
r := strings.NewReader("hello")
// bytes 當 reader
r := bytes.NewReader([]byte{1, 2, 3})
// 寫到 buffer
var buf bytes.Buffer
buf.WriteString("foo")
限制讀取量
limited := io.LimitReader(r, 1024) // 最多讀 1024 bytes
Tee:邊讀邊寫
// 讀 r 的同時,把資料寫到 w
tee := io.TeeReader(r, w)
io.ReadAll(tee) // 從 r 讀,同時 w 收到 copy
範例:計算 SHA256
import (
"crypto/sha256"
"io"
"os"
)
func hashFile(path string) ([]byte, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
h := sha256.New()
if _, err := io.Copy(h, f); err != nil {
return nil, err
}
return h.Sum(nil), nil
}
io.Copy 串流到 h,整個檔案不會載入記憶體。
io.Closer 與 RAII
type Closer interface {
Close() error
}
// 多數 IO 物件實作 ReadWriteCloser
type ReadWriteCloser interface {
Reader
Writer
Closer
}
打開的東西要 close。慣例:
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close() // 立刻 defer
encoding/json
Marshal / Unmarshal 基本
import "encoding/json"
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Email string `json:"email,omitempty"`
}
// Marshal
u := User{Name: "Alice", Age: 30}
b, err := json.Marshal(u)
// b: {"name":"Alice","age":30}
// Pretty print
b, _ := json.MarshalIndent(u, "", " ")
// Unmarshal
input := []byte(`{"name":"Bob","age":25,"email":"b@example.com"}`)
var u2 User
json.Unmarshal(input, &u2)
Struct Tag 細節
type T struct {
A int `json:"a"` // 對應 key "a"
B string `json:"b,omitempty"` // 空值省略("", 0, nil)
C int `json:"-"` // 完全不輸出
D string `json:"d,string"` // 字串包裝(給 JS 大數字保留精度用)
e int // 小寫不匯出,不會被處理
}
處理未知欄位
// 預設:多餘欄位被忽略
input := []byte(`{"name":"a","extra":"x"}`)
var u User
json.Unmarshal(input, &u) // 不報錯,extra 被丟掉
// 嚴格模式:未知欄位報錯
dec := json.NewDecoder(bytes.NewReader(input))
dec.DisallowUnknownFields()
err := dec.Decode(&u) // 報錯
動態 JSON
// 用 map
var data map[string]any
json.Unmarshal(input, &data)
// 用 json.RawMessage 保留原樣
type Event struct {
Type string `json:"type"`
Payload json.RawMessage `json:"payload"`
}
// 之後依 type 分別 decode payload
var e Event
json.Unmarshal(input, &e)
switch e.Type {
case "user.created":
var p UserCreated
json.Unmarshal(e.Payload, &p)
}
Streaming encoder/decoder(大檔)
// 編碼到 writer
enc := json.NewEncoder(w)
enc.SetIndent("", " ")
enc.Encode(data)
// 從 reader 解碼
dec := json.NewDecoder(r)
for dec.More() {
var item Item
if err := dec.Decode(&item); err != nil {
break
}
// 處理 item
}
自訂 MarshalJSON / UnmarshalJSON
當預設行為不符需求(例如 time.Time 想用特定格式):
type Date struct {
time.Time
}
const dateFormat = "2006-01-02"
func (d Date) MarshalJSON() ([]byte, error) {
return []byte(`"` + d.Format(dateFormat) + `"`), nil
}
func (d *Date) UnmarshalJSON(data []byte) error {
s := strings.Trim(string(data), `"`)
t, err := time.Parse(dateFormat, s)
if err != nil {
return err
}
d.Time = t
return nil
}
net/http 客戶端
最簡 GET
import (
"io"
"net/http"
)
resp, err := http.Get("https://api.example.com/users")
if err != nil {
return err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
POST JSON
import (
"bytes"
"encoding/json"
"net/http"
)
payload := map[string]string{"name": "Alice"}
b, _ := json.Marshal(payload)
resp, err := http.Post(
"https://api.example.com/users",
"application/json",
bytes.NewReader(b),
)
自訂 Request(加 header、timeout、context)
import (
"context"
"net/http"
"time"
)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.example.com", nil)
if err != nil {
return err
}
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("User-Agent", "myapp/1.0")
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Do(req)
⚠️ 預設 client 沒 timeout
http.Get(...) // 用 http.DefaultClient,timeout = 0 = 永不超時
生產用必須自訂 client:
client := &http.Client{
Timeout: 10 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
},
}
重用 client
http.Client 設計成可重用、執行緒安全 — 整個 process 共用一個就好:
var httpClient = &http.Client{Timeout: 10 * time.Second}
func fetchUser(ctx context.Context, id string) (*User, error) {
req, _ := http.NewRequestWithContext(ctx, "GET", "...", nil)
resp, err := httpClient.Do(req)
// ...
}
處理 response body
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close() // ⭐ 必須 close
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected status: %s", resp.Status)
}
var data Response
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
return err
}
注意:即使你不讀 body,也要 io.Copy(io.Discard, resp.Body) + Close,否則 connection 不能被重用。
net/http 伺服器
最簡 server
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, World!")
})
http.ListenAndServe(":8080", nil)
}
用 ServeMux 路由
mux := http.NewServeMux()
mux.HandleFunc("GET /users", listUsers) // Go 1.22+ 支援 method
mux.HandleFunc("GET /users/{id}", getUser) // 路徑參數
mux.HandleFunc("POST /users", createUser)
http.ListenAndServe(":8080", mux)
Go 1.22+ 內建 method-based routing 與 path parameter。
取路徑參數
func getUser(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id") // Go 1.22+
// ...
}
讀取 query / body
func handler(w http.ResponseWriter, r *http.Request) {
// Query
q := r.URL.Query().Get("q")
limit := r.URL.Query().Get("limit")
// JSON body
var payload struct {
Name string `json:"name"`
}
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
http.Error(w, "bad json", http.StatusBadRequest)
return
}
// Form
r.ParseForm()
name := r.FormValue("name")
}
回傳 JSON
func returnJSON(w http.ResponseWriter, data any, status int) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(data)
}
Middleware 模式
type Middleware func(http.Handler) http.Handler
func logging(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start))
})
}
func recover(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if rec := recover(); rec != nil {
log.Printf("panic: %v", rec)
http.Error(w, "Internal Server Error", 500)
}
}()
next.ServeHTTP(w, r)
})
}
// 串接
handler := logging(recover(mux))
http.ListenAndServe(":8080", handler)
Graceful shutdown
srv := &http.Server{
Addr: ":8080",
Handler: mux,
}
go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatal(err)
}
}()
// 等訊號
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
<-stop
// 30 秒內讓進行中的 request 跑完
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
srv.Shutdown(ctx)
time 套件
取現在時間
now := time.Now()
fmt.Println(now)
// 2026-05-16 10:00:00.123456789 +0800 CST
fmt.Println(now.UTC())
fmt.Println(now.Format(time.RFC3339))
// 2026-05-16T02:00:00Z
格式化的詭異點:用「2006-01-02」當範本
Go 用「2006 年 1 月 2 日 3 點 4 分 5 秒」當 layout,不是用 YYYY-MM-DD:
// 記憶法:1 2 3 4 5 6 7(月 日 時 分 秒 年 時區)
layout := "2006-01-02 15:04:05"
formatted := now.Format(layout)
常用 layout 常數
time.RFC3339 // "2006-01-02T15:04:05Z07:00"
time.RFC3339Nano // 帶 nanosecond
time.DateTime // "2006-01-02 15:04:05"
time.DateOnly // "2006-01-02"
time.TimeOnly // "15:04:05"
Parse 字串成 time
t, err := time.Parse(time.RFC3339, "2026-05-16T10:00:00Z")
t, err := time.Parse("2006-01-02", "2026-05-16")
// 含時區
loc, _ := time.LoadLocation("Asia/Taipei")
t, err := time.ParseInLocation("2006-01-02 15:04:05", "2026-05-16 10:00:00", loc)
Duration 操作
d := 5 * time.Second
d2 := time.Hour + 30*time.Minute
// 加減時間
future := now.Add(24 * time.Hour)
past := now.Add(-1 * time.Hour)
diff := future.Sub(now) // Duration
// 比較
if t1.Before(t2) { ... }
if t1.After(t2) { ... }
if t1.Equal(t2) { ... }
Sleep / Timer / Ticker
// 阻塞 sleep
time.Sleep(time.Second)
// 一次性 timer
<-time.After(time.Second) // 1 秒後 channel 有訊號
// 重複 ticker
tick := time.NewTicker(time.Second)
defer tick.Stop()
for {
select {
case <-tick.C:
fmt.Println("每秒一次")
case <-ctx.Done():
return
}
}
時區處理
loc, _ := time.LoadLocation("Asia/Taipei")
now := time.Now().In(loc) // 轉到指定時區
Production 慣例:
- 內部處理用 UTC
- 對使用者顯示時才轉本地時區
- 存資料庫永遠存 UTC
strings 與 strconv
strings 常用
import "strings"
strings.Contains("hello", "ell") // true
strings.HasPrefix("hello", "he") // true
strings.HasSuffix("hello", "lo") // true
strings.Index("hello", "ll") // 2
strings.Count("banana", "a") // 3
strings.Replace("hello", "l", "L", -1) // "heLLo"
strings.ReplaceAll("hello", "l", "L") // "heLLo"
strings.ToUpper("hello") // "HELLO"
strings.ToLower("HELLO") // "hello"
strings.Title("hello world") // 已 deprecated,改用 cases.Title
strings.TrimSpace(" x ") // "x"
strings.Trim("###x###", "#") // "x"
strings.Split("a,b,c", ",") // ["a", "b", "c"]
strings.Join([]string{"a","b","c"}, ",") // "a,b,c"
strings.Fields(" a b c ") // ["a", "b", "c"](空白拆)
strings.Repeat("ab", 3) // "ababab"
strings.Builder 高效拼字串
var b strings.Builder
for i := 0; i < 1000; i++ {
b.WriteString("a")
}
result := b.String()
比 s += "a" 快很多(避免重複 allocate)。
strconv 型別轉換
import "strconv"
// string → 數
n, err := strconv.Atoi("123")
i, err := strconv.ParseInt("123", 10, 64) // base 10, 64bit
u, err := strconv.ParseUint("123", 10, 64)
f, err := strconv.ParseFloat("3.14", 64)
b, err := strconv.ParseBool("true")
// 數 → string
s := strconv.Itoa(123)
s := strconv.FormatInt(123, 10)
s := strconv.FormatFloat(3.14, 'f', 2, 64) // "3.14"
s := strconv.FormatBool(true)
// 字串轉義(給 JSON / Go literal)
s := strconv.Quote("hello\nworld") // "\"hello\\nworld\""
os 與 os/exec
環境變數
import "os"
home := os.Getenv("HOME")
path, ok := os.LookupEnv("PATH") // 區分「不存在」與「空字串」
os.Setenv("FOO", "bar")
os.Unsetenv("FOO")
命令列參數
// os.Args[0] 是執行檔路徑
fmt.Println(os.Args[1:]) // 其他參數
// 用 flag 套件處理(更標準)
import "flag"
var (
port = flag.Int("port", 8080, "server port")
verbose = flag.Bool("v", false, "verbose")
)
flag.Parse()
檔案操作
// 讀整檔
data, err := os.ReadFile("config.json")
// 寫整檔(覆蓋)
err := os.WriteFile("out.txt", []byte("hello"), 0o644)
// Open + 串流讀
f, err := os.Open("big.log")
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text()
// ...
}
// Stat 取資訊
info, err := os.Stat("file.txt")
size := info.Size()
modTime := info.ModTime()
isDir := info.IsDir()
// 建目錄
os.Mkdir("foo", 0o755)
os.MkdirAll("a/b/c", 0o755) // 遞迴
// 移除
os.Remove("file.txt")
os.RemoveAll("foo/") // 遞迴
// 移動 / 改名
os.Rename("old.txt", "new.txt")
執行外部指令
import "os/exec"
// 簡單執行(同步)
out, err := exec.Command("ls", "-la").Output()
fmt.Println(string(out))
// 含 stderr
out, err := exec.Command("foo").CombinedOutput()
// 進階:自訂 stdin/stdout
cmd := exec.Command("grep", "ERROR")
cmd.Stdin = strings.NewReader("INFO: ok\nERROR: bad\n")
var out bytes.Buffer
cmd.Stdout = &out
cmd.Run()
// 帶 context(可超時取消)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
out, err := exec.CommandContext(ctx, "slow-cmd").Output()
// 取得 exit code
err := exec.Command("foo").Run()
if exitErr, ok := err.(*exec.ExitError); ok {
fmt.Println("exit code:", exitErr.ExitCode())
}
訊號處理
import (
"os"
"os/signal"
"syscall"
)
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
<-sigCh
fmt.Println("收到結束訊號")
實戰範例
範例 1:完整 HTTP API(client 呼外部 + server 回 JSON)
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"time"
)
var httpClient = &http.Client{Timeout: 10 * time.Second}
type Weather struct {
City string `json:"city"`
Temperature float64 `json:"temp"`
}
func fetchWeather(ctx context.Context, city string) (*Weather, error) {
url := fmt.Sprintf("https://api.example.com/weather?city=%s", city)
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
resp, err := httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("unexpected status: %d", resp.StatusCode)
}
var w Weather
if err := json.NewDecoder(resp.Body).Decode(&w); err != nil {
return nil, err
}
return &w, nil
}
func handler(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
defer cancel()
city := r.URL.Query().Get("city")
if city == "" {
http.Error(w, "city required", http.StatusBadRequest)
return
}
weather, err := fetchWeather(ctx, city)
if err != nil {
http.Error(w, err.Error(), http.StatusBadGateway)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(weather)
}
func main() {
http.HandleFunc("/weather", handler)
log.Println("listening :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
範例 2:CSV 串流處理(大檔不爆記憶體)
package main
import (
"encoding/csv"
"fmt"
"io"
"os"
)
func main() {
f, err := os.Open("big.csv")
if err != nil {
panic(err)
}
defer f.Close()
r := csv.NewReader(f)
// 跳 header
if _, err := r.Read(); err != nil {
panic(err)
}
for {
record, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
panic(err)
}
fmt.Println(record)
}
}
範例 3:執行 shell 指令並 timeout
package main
import (
"context"
"fmt"
"os/exec"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
out, err := exec.CommandContext(ctx, "sh", "-c", "sleep 10 && echo done").Output()
if err != nil {
if ctx.Err() == context.DeadlineExceeded {
fmt.Println("超時")
return
}
fmt.Println("失敗:", err)
return
}
fmt.Println(string(out))
}
範例 4:定期 ticker 配合 graceful shutdown
package main
import (
"context"
"fmt"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
ctx, cancel := signal.NotifyContext(context.Background(),
os.Interrupt, syscall.SIGTERM)
defer cancel()
tick := time.NewTicker(time.Second)
defer tick.Stop()
for {
select {
case <-ctx.Done():
fmt.Println("\nshutting down")
return
case t := <-tick.C:
fmt.Println("tick at", t.Format(time.RFC3339))
}
}
}
最佳實踐
1. 永遠 close response body
resp, err := client.Do(req)
if err != nil { return err }
defer resp.Body.Close() // ⭐
2. http.Client 設 timeout 並重用
// ✅
var client = &http.Client{Timeout: 10 * time.Second}
// ❌ 用預設 client(無 timeout)
http.Get(...)
3. JSON 用 streaming(大資料)
// ❌ 小資料 OK,大檔吃光記憶體
data, _ := io.ReadAll(resp.Body)
json.Unmarshal(data, &v)
// ✅ 串流
json.NewDecoder(resp.Body).Decode(&v)
4. 時間處理永遠用 UTC(內部)
// ✅
t := time.Now().UTC()
db.Save(t)
// 顯示給使用者才轉本地時區
loc, _ := time.LoadLocation("Asia/Taipei")
display := t.In(loc).Format(time.DateTime)
5. strings.Builder 取代 +=
// ❌ O(n²)
s := ""
for _, x := range items {
s += x
}
// ✅ O(n)
var b strings.Builder
for _, x := range items {
b.WriteString(x)
}
s := b.String()
6. exec 加 context 防卡住
// ❌ 可能永遠卡住
exec.Command("foo").Run()
// ✅ 有上限
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
exec.CommandContext(ctx, "foo").Run()
7. 檢查 status code 與 error 分開
resp, err := client.Do(req)
if err != nil {
// 網路層失敗
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
// 應用層失敗(4xx/5xx)
return fmt.Errorf("unexpected status: %d", resp.StatusCode)
}
常見問題
問題 1:http.Get 沒 timeout 卡死
症狀:HTTP 呼叫掛住整個 process
原因:http.DefaultClient 的 Timeout = 0 = 永不超時
解決:自訂 client
client := &http.Client{Timeout: 10 * time.Second}
問題 2:JSON Unmarshal 把空字串當數字 fail
症狀:API 回傳 {"count": ""},但 struct 是 int
解決:用 *int 或自訂 UnmarshalJSON:
type Response struct {
Count *int `json:"count"` // 可為 nil
}
問題 3:time.Parse 噴 cannot parse
原因:layout 字串寫錯,必須是 2006-01-02 15:04:05 那組魔法數字
// ❌ 直覺寫法
time.Parse("YYYY-MM-DD", "2026-05-16")
// ✅ 正確
time.Parse("2006-01-02", "2026-05-16")
問題 4:os.ReadFile 大檔吃光記憶體
解決:用 bufio.Scanner 或 io.Copy 串流處理
f, _ := os.Open(path)
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text()
// ...
}
問題 5:exec.Output 拿不到 stderr
原因:Output() 只拿 stdout
解決:用 CombinedOutput 或自訂 cmd.Stderr:
out, err := exec.Command("foo").CombinedOutput()
// 或
var stderr bytes.Buffer
cmd := exec.Command("foo")
cmd.Stderr = &stderr
cmd.Run()
fmt.Println("stderr:", stderr.String())
問題 6:goroutine leak 因為沒 close body
// ❌ 不 close → connection 不能 reuse → TCP 連線累積
resp, _ := client.Do(req)
// 沒 defer resp.Body.Close()
return
總結
核心要點
io.Reader/Writer 是 Go IO 抽象之根
json 用 streaming 處理大檔
http.Client 永遠設 timeout 並重用
time 用 UTC 內部、本地時區顯示
exec 永遠加 context
設計原則:
- ✅ http.Client 重用 + timeout
- ✅ resp.Body 必須 close
- ✅ time 內部 UTC、顯示本地時區
- ✅ strings.Builder 取代 +=
- ✅ exec / http 永遠加 context
速查表
// io
io.Copy(dst, src)
io.ReadAll(r)
io.LimitReader(r, n)
// json
json.Marshal(v); json.Unmarshal(b, &v)
json.NewEncoder(w).Encode(v)
json.NewDecoder(r).Decode(&v)
// http client
client := &http.Client{Timeout: 10 * time.Second}
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
resp, _ := client.Do(req)
defer resp.Body.Close()
// http server
mux := http.NewServeMux()
mux.HandleFunc("GET /path", handler)
srv := &http.Server{Addr: ":8080", Handler: mux}
srv.ListenAndServe()
srv.Shutdown(ctx)
// time
now := time.Now()
now.Format(time.RFC3339)
time.Parse("2006-01-02", "2026-05-16")
time.Sleep(time.Second)
// strings/strconv
strings.Split(s, ",")
strings.Join(arr, ",")
strconv.Atoi("123")
strconv.Itoa(123)
// os/exec
out, _ := exec.CommandContext(ctx, "ls").Output()
Time Layout 速查
| 想要的格式 | Layout |
|---|---|
| 2026-05-16 | 2006-01-02 |
| 2026-05-16 10:00:00 | 2006-01-02 15:04:05 |
| 2026-05-16T10:00:00Z | time.RFC3339 |
| 10:00 AM | 3:04 PM |
| Mon, 16 May 2026 | Mon, 02 Jan 2006 |
相關閱讀
- Go Context — http/exec 都吃 context
- Go 錯誤處理 — io.EOF / context.Canceled
- Go 測試 — httptest 測 HTTP handler
- Go 建置與發佈 —
go:embed嵌入靜態資源
參考資源
- 官方 standard library:https://pkg.go.dev/std
- net/http:https://pkg.go.dev/net/http
- encoding/json:https://pkg.go.dev/encoding/json
- time:https://pkg.go.dev/time
- Effective Go:https://go.dev/doc/effective_go
建立日期:2026-05-16 最後更新:2026-05-16