課程總覽
本網站採用章節式導覽與範例驅動學習方式,從入門語法一路擴展到 Web 開發、並行處理與 generics。
建立專案、執行第一支 Go 程式。
package、import、main、輸出與註解。
變數、零值、型別推斷與基本型別。
列舉值、位元旗標與狀態定義。
理解位址、解參考與傳址修改。
if、switch、for、range。
多回傳值、error、defer。
最常用容器資料結構。
封裝資料與抽象行為。
拆分專案與重用程式碼。
常見資料交換與檔案操作。
面向實務的中高階主題。
安裝與 Hello World
從建立目錄、初始化 module 到執行第一支程式,是 Go 新手最標準的起點。
建立第一個專案
- 安裝 Go
- 建立資料夾
hello - 執行
go mod init example/hello - 建立
hello.go - 執行
go run .
初始化專案
mkdir hello
cd hello
go mod init example/hello
go run .
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
Go 語法基礎
Go 程式通常由 package、import 與 main function 組成,語法簡潔、風格一致。
package
用於組織程式碼;執行程式常用 main 套件。
import
引入標準函式庫,例如 fmt、os、net/http。
註解
單行用 //,多行用 /* ... */。
package main
import "fmt"
// main 是程式入口
func main() {
fmt.Println("Go 語法學習開始!")
}
變數與型別
Go 支援明確型別與型別推斷,也有零值概念,這是後續理解資料結構與記憶體操作的基礎。
| 型別 | 範例 | 說明 |
|---|---|---|
| int | 10 | 整數 |
| float64 | 3.14 | 浮點數 |
| string | "Hello" | 字串 |
| bool | true / false | 布林值 |
package main
import "fmt"
func main() {
var age int = 18
language := "Go"
isFast := true
fmt.Println(age)
fmt.Println(language)
fmt.Println(isFast)
}
重點整理
var name type = value:完整宣告name := value:簡短宣告,只能在函式內使用- 未初始化變數會有零值
- Go 重視明確型別與可預測行為
常數與 iota
Go 的常數可以是 typed 或 untyped,iota 常用來建立一組連續值,例如列舉、狀態碼或位元旗標。
重點觀念
- 常數不可在執行期間被改變
- Go 有 typed constants 與 untyped constants
iota只在 const 宣告區塊中使用- 常見用途:狀態列舉、權限位元、流程代碼
package main
import "fmt"
const (
Pending = iota
Approved
Rejected
)
func main() {
fmt.Println(Pending)
fmt.Println(Approved)
fmt.Println(Rejected)
}
package main
import "fmt"
const (
Read = 1 << iota
Write
Execute
)
func main() {
fmt.Println(Read)
fmt.Println(Write)
fmt.Println(Execute)
}
Pointer 指標
Pointer 儲存變數位址,能讓函式直接修改原始資料。未初始化的 pointer 其值為 nil。
package main
import "fmt"
func main() {
x := 10
p := &x
fmt.Println(x)
*p = 20
fmt.Println(x)
}
package main
import "fmt"
func addFive(n *int) {
*n += 5
}
func main() {
score := 10
addFive(&score)
fmt.Println(score)
}
條件與迴圈
Go 沒有 while,主要使用 for;另外 if 與 switch 可以帶初始化敘述。
package main
import "fmt"
func main() {
score := 85
if score >= 60 {
fmt.Println("及格")
} else {
fmt.Println("不及格")
}
}
package main
import "fmt"
func main() {
for i := 0; i < 5; i++ {
fmt.Println(i)
}
}
range 是 Go 中遍歷 slice、map、array、string 的常用方式。
函式與錯誤處理
Go 的函式可回傳多個值,這讓錯誤處理模式清晰直接。defer 常用於資源釋放與收尾操作。
package main
import "fmt"
func add(a int, b int) int {
return a + b
}
func main() {
fmt.Println(add(5, 7))
}
package main
import "fmt"
func main() {
defer fmt.Println("結束前執行 defer")
fmt.Println("開始")
}
package main
import "fmt"
func divide(a, b int) (int, int) {
return a / b, a % b
}
func main() {
q, r := divide(10, 2)
fmt.Println("商為:", q)
fmt.Println("餘數:", r)
}
陣列 / Slice / Map
切片與映射是 Go 中最常用的資料容器之一,理解長度、容量、append 與 key/value 操作非常重要。
package main
import "fmt"
func main() {
langs := []string{"Go", "Java"}
langs = append(langs, "Python")
fmt.Println(langs)
fmt.Println(len(langs))
}
package main
import "fmt"
func main() {
student := map[string]interface{}{
"name": "Alice",
"score": 95,
}
fmt.Println(student["name"])
fmt.Println(student["score"])
}
make 常用來建立 slice、map、channel;而 new 與 make 的用途不同,是 Go 初學的重要觀念。
Struct / Method / Interface
Go 沒有傳統 class,但可以用 struct、method、interface 建構清楚且可維護的抽象設計。
package main
import "fmt"
type User struct {
Name string
}
func (u User) Greet() string {
return "Hi, 我是 " + u.Name
}
func main() {
user := User{Name: "Gopher"}
fmt.Println(user.Greet())
}
package main
import "fmt"
type Speaker interface {
Speak() string
}
type Dog struct{}
func (d Dog) Speak() string {
return "汪!"
}
func main() {
var s Speaker = Dog{}
fmt.Println(s.Speak())
}
Package 拆分與模組
Go 程式碼以 package 組織,package 再被歸屬到 module 中。實務上會把功能拆成多個 package 來維持可讀性與可重用性。
範例目錄結構
myapp/
├─ go.mod
├─ main.go
└─ utils/
└─ math.go
建立模組
go mod init example.com/myapp
// utils/math.go
package utils
func Add(a int, b int) int {
return a + b
}
// main.go
package main
import (
"fmt"
"example.com/myapp/utils"
)
func main() {
fmt.Println(utils.Add(3, 5))
}
JSON 處理
Go 標準套件 encoding/json 支援資料編碼與解碼,最重要的是 json.Marshal、json.Unmarshal 與 struct tag。
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
u := User{Name: "Alice", Age: 20}
data, _ := json.Marshal(u)
fmt.Println(string(data))
}
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
text := `{"name":"Bob","age":25}`
var u User
json.Unmarshal([]byte(text), &u)
fmt.Println(u.Name)
fmt.Println(u.Age)
}
omitempty、MarshalIndent、Decoder 與 Encoder 的教學。
File I/O 檔案操作
Go 初學最常用的是 os.ReadFile 與 os.WriteFile,進一步才會學 os.Open、os.Create、Read、Write 與 Close。
package main
import (
"fmt"
"os"
)
func main() {
err := os.WriteFile("hello.txt", []byte("Hello Go File"), 0644)
if err != nil {
fmt.Println("寫入失敗:", err)
return
}
fmt.Println("寫入完成")
}
package main
import (
"fmt"
"os"
)
func main() {
data, err := os.ReadFile("hello.txt")
if err != nil {
fmt.Println("讀取失敗:", err)
return
}
fmt.Println(string(data))
}
HTTP Server
Go 的 net/http 是內建的 Web 開發基礎。最常見的入門方式是 http.HandleFunc 搭配 http.ListenAndServe。
package main
import (
"fmt"
"net/http"
)
func home(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "歡迎來到 Go HTTP Server")
}
func main() {
http.HandleFunc("/", home)
fmt.Println("伺服器啟動於 http://localhost:8080")
http.ListenAndServe(":8080", nil)
}
REST API 範例
REST API 教學可結合 net/http 與 encoding/json,示範回傳 JSON、解析請求與建立簡單資源列表。
package main
import (
"encoding/json"
"net/http"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
func usersHandler(w http.ResponseWriter, r *http.Request) {
users := []User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
}
func main() {
http.HandleFunc("/users", usersHandler)
http.ListenAndServe(":8080", nil)
}
這章可再擴充
- GET /users
- GET /users/{id}
- POST /users
- PUT /users/{id}
- DELETE /users/{id}
教學建議
這一章很適合加入 Postman 測試說明、status code、request body 解析、路由拆分與錯誤回應格式。
Goroutine / Channel
並行是 Go 的核心魅力之一。教學站應展示 goroutine、channel、同步思維與常見範例。
package main
import "fmt"
func main() {
ch := make(chan string)
go func() {
ch <- "Hello from goroutine"
}()
msg := <-ch
fmt.Println("收到訊息:", msg)
}
Goroutine + Worker Pool
Worker Pool 是 Go 並行教學中的經典範例,能幫助使用者理解 jobs channel、results channel 與 goroutine 協作。
package main
import "fmt"
func worker(id int, jobs <-chan int, results chan<- int) {
for job := range jobs {
fmt.Println("worker", id, "處理工作", job)
results <- job * 2
}
}
func main() {
jobs := make(chan int, 3)
results := make(chan int, 3)
go worker(1, jobs, results)
go worker(2, jobs, results)
jobs <- 1
jobs <- 2
jobs <- 3
close(jobs)
fmt.Println("結果:", <-results)
fmt.Println("結果:", <-results)
fmt.Println("結果:", <-results)
}
Generics 基礎
Go 的 generics 讓你可以為多種型別撰寫共用邏輯。核心概念包含 type parameters、constraints、comparable 與 type inference。
重點觀念
- 使用方括號宣告 type parameters
- constraint 限定可接受的型別
comparable常用於 map key 或比對- Go 可在呼叫時自動做 type inference
package main
import "fmt"
type Number interface {
int | float64
}
func Sum[T Number](a, b, c T) T {
return a + b + c
}
func main() {
fmt.Println(Sum(1, 2, 3))
fmt.Println(Sum(1.5, 2.5, 3.5))
}