Go for beginnersGo สำหรับผู้เริ่มต้น
Go Beginner Guide
From your first program to a tested JSON APIตั้งแต่โปรแกรมแรกจนถึง JSON API ที่มีเทสต์
Go is a small, fast language made at Google. It runs Docker, Kubernetes, Terraform and much of the cloud. This guide teaches it from the first line: variables, strings, slices, maps, functions, structs, interfaces, errors and goroutines, then a real web server with tests. The examples on this page run in your browser. Change the code, press Run, and see what happens. Go เป็นภาษาที่เล็กและเร็ว สร้างโดย Google และเป็นภาษาที่ใช้สร้าง Docker, Kubernetes, Terraform และระบบคลาวด์อีกมาก คู่มือนี้สอนตั้งแต่บรรทัดแรก: ตัวแปร ข้อความ slice, map ฟังก์ชัน struct, interface, error และ goroutine แล้วจบด้วยเว็บเซิร์ฟเวอร์จริงที่มีเทสต์ ตัวอย่างในหน้านี้รันได้ในเบราว์เซอร์ ลองแก้โค้ด กด Run แล้วดูว่าเกิดอะไรขึ้น
Shortcut: pressคีย์ลัด: กด Ctrl+Enter (⌘+Enter Mac) inside a code box to run it. The first run downloads the Go runner (about 3 MB).ในกล่องโค้ดเพื่อรันทันที การรันครั้งแรกจะดาวน์โหลดตัวรัน Go (ประมาณ 3 MB)
- Recorded withบันทึกด้วย Go 1.25.4
- Runs in browserรันในเบราว์เซอร์ Yaegi (WebAssembly)
- Testsเทสต์ go test
The languageตัวภาษา
Variables, strings, slices, maps, functions, structs, interfaces and errors.ตัวแปร ข้อความ slice, map ฟังก์ชัน struct, interface และ error
Lessons 2–10 →บทที่ 2–10 →Concurrencyการทำงานพร้อมกัน
Do several things at once with goroutines and channels.ทำหลายงานพร้อมกันด้วย goroutine และ channel
Lesson 11 →บทที่ 11 →A real programโปรแกรมจริง
Packages, a JSON API with net/http, and go test.package, JSON API ด้วย net/http และ go test
Lessons 12–14 →บทที่ 12–14 →Lesson 1 · Setupบทที่ 1 · ติดตั้ง
Getting startedเริ่มต้นใช้งาน
Go is a compiled language: the go tool turns your code into a single program file that runs on its own, with nothing else to install on the server. Install Go, then check it works:
Go เป็นภาษาแบบคอมไพล์ เครื่องมือ go จะแปลงโค้ดเป็นไฟล์โปรแกรมไฟล์เดียวที่รันได้ด้วยตัวเอง โดยไม่ต้องติดตั้งอะไรเพิ่มบนเซิร์ฟเวอร์ ติดตั้ง Go แล้วตรวจว่าใช้งานได้:
| Systemระบบ | Installวิธีติดตั้ง |
|---|---|
| macOS | brew install go |
| Windows | winget install GoLang.Go or the installer from go.dev/dlหรือตัวติดตั้งจาก go.dev/dl |
| Linux | the archive from go.dev/dl (distro packages are often old)ไฟล์ archive จาก go.dev/dl (แพ็กเกจของ distro มักเป็นเวอร์ชันเก่า) |
Every Go program lives in a module, a folder with a go.mod file. Create one, write main.go, and run it:
โปรแกรม Go ทุกตัวอยู่ใน module ซึ่งก็คือโฟลเดอร์ที่มีไฟล์ go.mod สร้าง module เขียน main.go แล้วรัน:
$ go version go version go1.25.4 darwin/arm64 $ mkdir hello && cd hello $ go mod init example.com/hello go: creating new go.mod: module example.com/hello $ go run . Hello, Go! $ go build && ls go.mod hello main.go $ ./hello Hello, Go!
go run . compiles and runs in one step. go build leaves a program file, hello, that you can copy to a server and run there without Go installed.go run . คอมไพล์และรันในขั้นตอนเดียว ส่วน go build จะได้ไฟล์โปรแกรมชื่อ hello ที่คัดลอกไปรันบนเซิร์ฟเวอร์ได้โดยไม่ต้องติดตั้ง Go
package mainandfunc main()mark the program's starting point.package mainและfunc main()คือจุดเริ่มต้นของโปรแกรมimport "fmt"loads the formatting package. Go refuses to compile if you import something and don't use it.import "fmt"โหลด package สำหรับจัดรูปแบบข้อความ Go จะไม่ยอมคอมไพล์ถ้า import แล้วไม่ได้ใช้- No semicolons, and the opening
{must stay on the same line asfunc,iforfor.ไม่ต้องมีเซมิโคลอน และ{ต้องอยู่บรรทัดเดียวกับfunc,ifหรือfor
Run uses Yaegi, a Go interpreter, compiled to WebAssembly. Normal programs behave the same as with go run, but Yaegi skips some compiler checks (an unused variable is allowed) and words some errors differently. For those cases, trust the recorded output and lesson 16.ปุ่ม Run ใช้ Yaegi ซึ่งเป็นตัวแปลภาษา Go ที่คอมไพล์เป็น WebAssembly โปรแกรมทั่วไปทำงานเหมือน go run แต่ Yaegi ข้ามการตรวจบางอย่างของคอมไพเลอร์ (เช่น ยอมให้มีตัวแปรที่ไม่ได้ใช้) และใช้ถ้อยคำในข้อความผิดพลาดต่างออกไป ในกรณีเหล่านั้นให้เชื่อผลลัพธ์ที่บันทึกไว้และบทที่ 16
Lesson 2 · The basicsบทที่ 2 · พื้นฐาน
Variables & typesตัวแปรและชนิดข้อมูล
Every value in Go has a fixed type, checked before the program runs. Inside a function, := declares a variable and lets Go work out its type. A variable you declare without a value gets its type's zero value, so there's no "undefined" in Go.
ทุกค่าใน Go มีชนิดข้อมูล (type) ที่ตายตัวและถูกตรวจก่อนโปรแกรมทำงาน ภายในฟังก์ชัน := ใช้ประกาศตัวแปรโดยให้ Go หาชนิดเอง ตัวแปรที่ประกาศโดยไม่ให้ค่าจะได้ค่าศูนย์ (zero value) ของชนิดนั้น Go จึงไม่มีค่า "undefined"
| Typeชนิด | Holdsเก็บอะไร | Zero valueค่าศูนย์ |
|---|---|---|
int | whole numberจำนวนเต็ม | 0 |
float64 | decimal numberเลขทศนิยม | 0 |
string | textข้อความ | "" |
bool | true or falseจริงหรือเท็จ | false |
[]T, map[K]V, pointersพอยน์เตอร์ | lessons 6–8บทที่ 6–8 | nil |
Use := inside functions; it's what you'll see in almost all Go code. var is for package-level variables and for when you want the zero value. Go never converts between types for you: age * 1.5 is a compile error until you write float64(age).ใช้ := ภายในฟังก์ชัน ซึ่งเป็นสิ่งที่เห็นในโค้ด Go เกือบทั้งหมด ส่วน var ใช้กับตัวแปรระดับ package และเมื่อต้องการค่าศูนย์ Go ไม่แปลงชนิดให้เองเลย age * 1.5 จะคอมไพล์ไม่ผ่านจนกว่าจะเขียน float64(age)
Lesson 3 · Textบทที่ 3 · ข้อความ
Strings & runesข้อความและ rune
The strings package has a function for almost every text job. Strings can't be changed in place, so these functions return a new string.
package strings มีฟังก์ชันสำหรับงานข้อความแทบทุกอย่าง string แก้ไขในตัวเองไม่ได้ ฟังก์ชันเหล่านี้จึงคืน string ใหม่
Bytes, runes and Thai textไบต์ rune และข้อความภาษาไทย
A Go string is a sequence of bytes in UTF-8. len() counts bytes, and a Thai letter takes three. A rune is one Unicode character. range over a string gives you runes, and []rune(s) lets you cut by character instead of by byte.
string ใน Go คือลำดับของไบต์ในรูปแบบ UTF-8 len() นับเป็นไบต์ และตัวอักษรไทยใช้สามไบต์ rune คืออักขระ Unicode หนึ่งตัว การใช้ range กับ string จะได้ rune ออกมา และ []rune(s) ช่วยให้ตัดเป็นตัวอักษรแทนการตัดเป็นไบต์
The count is 6, not 5, because vowel and tone marks such as ั and ี are separate runes. The positions jump by 3 because each Thai letter is 3 bytes. The � is half a letter that can't be drawn.นับได้ 6 ไม่ใช่ 5 เพราะสระและวรรณยุกต์ เช่น ั และ ี เป็น rune แยกกัน ตำแหน่งกระโดดทีละ 3 เพราะตัวอักษรไทยแต่ละตัวมี 3 ไบต์ ส่วน � คือตัวอักษรครึ่งตัวที่แสดงไม่ได้
Lesson 4 · Selectionบทที่ 4 · การเลือก
Decisionsการตัดสินใจ
if needs no parentheses, but always needs braces. It can start with a short statement, which is how Go code checks errors in one line. switch stops after the matching case, so there's no break to forget.
if ไม่ต้องมีวงเล็บ แต่ต้องมีวงเล็บปีกกาเสมอ และเริ่มด้วยคำสั่งสั้นๆ ได้ ซึ่งเป็นวิธีที่โค้ด Go ใช้ตรวจ error ในบรรทัดเดียว ส่วน switch จะหยุดหลัง case ที่ตรง จึงไม่มี break ให้ลืม
| Writeเขียน | Meansความหมาย |
|---|---|
== != | equal / not equal (always strict: both sides must be the same type)เท่ากับ / ไม่เท่ากับ (เข้มงวดเสมอ: ทั้งสองฝั่งต้องเป็นชนิดเดียวกัน) |
> < >= <= | bigger, smaller, or equalมากกว่า น้อยกว่า หรือเท่ากับ |
&& || ! | and, or, notและ หรือ ไม่ |
There is no ? : operator, no "truthy" values, and if x only works when x is a bool. Write the comparison out: if count > 0.Go ไม่มีตัวดำเนินการ ? : ไม่มีค่าที่ "นับเป็นจริง" และ if x ใช้ได้เฉพาะเมื่อ x เป็น bool ต้องเขียนการเปรียบเทียบให้ชัด เช่น if count > 0
Lesson 5 · Repetitionบทที่ 5 · การวนซ้ำ
Loopsการวนซ้ำ
Go has one loop keyword: for. It counts, it works like while when you give it only a condition, and with range it walks through slices, maps and strings.
Go มีคำสั่งวนซ้ำเพียงคำเดียวคือ for ใช้นับรอบได้ ทำงานเหมือน while เมื่อให้แค่เงื่อนไข และเมื่อใช้กับ range จะเดินผ่าน slice, map และ string
Newer Go can also count with for i := range 3 (0, 1, 2). The browser runner doesn't support that form yet, so the labs use the classic loop, which works everywhere. Try deleting left-- and pressing Run: the page stops the endless loop after 6 seconds.Go รุ่นใหม่นับรอบด้วย for i := range 3 (ได้ 0, 1, 2) ได้ด้วย แต่ตัวรันในเบราว์เซอร์ยังไม่รองรับรูปแบบนี้ แล็บจึงใช้ลูปแบบคลาสสิกที่ใช้ได้ทุกที่ ลองลบ left-- แล้วกด Run หน้านี้จะหยุดลูปไม่รู้จบให้หลัง 6 วินาที
Lesson 6 · Dataบทที่ 6 · ข้อมูล
Slices & mapsSlice และ map
A slice ([]int) is a list that can grow. append adds to it and returns the new slice, which you must store. Cutting a slice with s[a:b] doesn't copy: both slices share the same underlying memory.
slice ([]int) คือรายการที่ขยายได้ append ใช้เพิ่มข้อมูลและคืน slice ใหม่ ซึ่งต้องเก็บไว้เสมอ การตัด slice ด้วย s[a:b] ไม่ได้คัดลอก ทั้งสอง slice ใช้หน่วยความจำชุดเดียวกัน
A map (map[string]int) looks values up by key. Reading a missing key gives the zero value, so use the "comma ok" form when you need to know whether it was there. Map order is random on purpose: sort the keys when the order matters.
map (map[string]int) ใช้ค้นหาค่าด้วยคีย์ การอ่านคีย์ที่ไม่มีอยู่จะได้ค่าศูนย์ จึงต้องใช้รูปแบบ "comma ok" เมื่ออยากรู้ว่ามีคีย์นั้นหรือไม่ ลำดับใน map ถูกสุ่มโดยตั้งใจ ถ้าลำดับสำคัญให้เรียงคีย์ก่อน
| Codeโค้ด | Doesทำอะไร |
|---|---|
s := []int{1, 2} | a slice with valuesslice ที่มีค่า |
s = append(s, 3) | add to the endเพิ่มต่อท้าย |
len(s) | number of itemsจำนวนสมาชิก |
s[1:3] | items 1 and 2 (shares memory)สมาชิกตัวที่ 1 และ 2 (ใช้หน่วยความจำร่วม) |
slices.Contains(s, 3) | is this value in the slice?มีค่านี้ใน slice ไหม |
m := map[string]int{} | an empty map, ready to usemap ว่างที่พร้อมใช้ |
v, ok := m["k"] | read, and know if the key existsอ่านค่า และรู้ว่ามีคีย์นี้หรือไม่ |
delete(m, "k") | remove a keyลบคีย์ |
Lesson 7 · Reuseบทที่ 7 · การนำกลับมาใช้ซ้ำ
Functionsฟังก์ชัน
Types come after names: func add(a, b int) int. A Go function can return several values, which is how it reports errors: a result plus an error that is nil when everything went fine. Functions are values too, so you can store them and return them.
ชนิดข้อมูลเขียนหลังชื่อ เช่น func add(a, b int) int ฟังก์ชัน Go คืนค่าได้หลายค่า ซึ่งเป็นวิธีรายงาน error: คืนผลลัพธ์พร้อม error ที่เป็น nil เมื่อทุกอย่างเรียบร้อย ฟังก์ชันก็เป็นค่าเช่นกัน จึงเก็บไว้ในตัวแปรหรือคืนออกมาได้
defer schedules a call for when the surrounding function returns, even if it returns early. It's how Go closes files and unlocks locks: you write the clean-up right next to the thing that needs it.defer นัดให้เรียกคำสั่งตอนที่ฟังก์ชันรอบนอกจบ แม้จะจบก่อนกำหนดก็ตาม เป็นวิธีที่ Go ใช้ปิดไฟล์และปลดล็อก โดยเขียนการเก็บกวาดไว้ข้างๆ สิ่งที่ต้องเก็บกวาด
Lesson 8 · Your own typesบทที่ 8 · ชนิดข้อมูลของเราเอง
Structs & methodsStruct และ method
Go has no classes. A struct groups fields, and methods are functions attached to a type. A name that starts with a capital letter is visible to other packages; a lower-case name is private to its package. A method with a pointer receiver (*Account) can change the struct; one with a value receiver works on a copy.
Go ไม่มีคลาส struct ใช้รวมฟิลด์เข้าด้วยกัน และ method คือฟังก์ชันที่ผูกกับชนิดข้อมูล ชื่อที่ขึ้นต้นด้วยตัวพิมพ์ใหญ่ package อื่นมองเห็นได้ ส่วนชื่อตัวพิมพ์เล็กใช้ได้เฉพาะใน package ของมัน method ที่มี pointer receiver (*Account) แก้ไข struct ได้ ส่วน value receiver ทำงานกับสำเนา
| Writeเขียน | Meansความหมาย |
|---|---|
type Point struct{ X, Y int } | a new struct typeชนิด struct ใหม่ |
p := Point{X: 1, Y: 2} | a value with named fieldsค่าพร้อมระบุชื่อฟิลด์ |
&Point{} | a pointer to a new valueพอยน์เตอร์ไปยังค่าใหม่ |
func (p *Point) Move() | a method that can change pmethod ที่แก้ไข p ได้ |
Name / name | exported / private to the packagepackage อื่นใช้ได้ / ใช้ได้เฉพาะใน package |
Lesson 9 · Behaviourบทที่ 9 · พฤติกรรม
InterfacesInterface
An interface lists methods. Any type that has those methods satisfies it automatically; there's no implements keyword. That lets a function accept "anything with an Area()" without knowing the concrete types.
interface คือรายการของ method ชนิดข้อมูลใดที่มี method ครบก็เป็น interface นั้นโดยอัตโนมัติ ไม่ต้องมีคำว่า implements ทำให้ฟังก์ชันรับ "อะไรก็ได้ที่มี Area()" โดยไม่ต้องรู้ชนิดที่แท้จริง
Keep interfaces small. The most used ones in Go have a single method: error (Error() string), fmt.Stringer (String() string) and io.Reader (Read(p []byte) (int, error)).ทำ interface ให้เล็ก interface ที่ใช้บ่อยที่สุดใน Go มี method เดียว ได้แก่ error (Error() string), fmt.Stringer (String() string) และ io.Reader (Read(p []byte) (int, error))
Lesson 10 · When things go wrongบทที่ 10 · เมื่อเกิดปัญหา
ErrorsError
Go has no exceptions for everyday problems. A function that can fail returns an error as its last result, and the caller checks it straight away with if err != nil. You'll write that line a lot; it keeps every failure visible right where it happens.
Go ไม่ใช้ exception กับปัญหาทั่วไป ฟังก์ชันที่อาจล้มเหลวจะคืน error เป็นค่าสุดท้าย และผู้เรียกตรวจทันทีด้วย if err != nil จะได้เขียนบรรทัดนี้บ่อยมาก เพราะทำให้เห็นทุกความล้มเหลวตรงจุดที่เกิด
| Codeโค้ด | Doesทำอะไร |
|---|---|
errors.New("msg") | a simple error valueค่า error แบบง่าย |
fmt.Errorf("doing x: %w", err) | add context and keep the originalเพิ่มบริบทและเก็บ error เดิมไว้ |
errors.Is(err, ErrNotFound) | is this (or a wrapped) error that one?error นี้ (หรือที่ถูกห่อไว้) ใช่ตัวนั้นไหม |
panic(...) | stop the program: only for bugs that should never happenหยุดโปรแกรม: ใช้กับบั๊กที่ไม่ควรเกิดขึ้นเท่านั้น |
Reading past the end of a slice or writing to a nil map makes Go panic: the program stops and prints a stack trace. Lesson 16 shows the real messages. Treat a panic as a bug to fix, not as an error to handle.การอ่านเกินขอบ slice หรือเขียนลง map ที่เป็น nil จะทำให้ Go panic คือโปรแกรมหยุดและพิมพ์ stack trace บทที่ 16 แสดงข้อความจริง ให้ถือว่า panic คือบั๊กที่ต้องแก้ ไม่ใช่ error ที่ต้องจัดการ
Lesson 11 · Doing many things at onceบทที่ 11 · ทำหลายอย่างพร้อมกัน
Goroutines & channelsGoroutine และ channel
Put go in front of a function call and it runs in a goroutine, alongside the rest of your program. Goroutines are cheap; a server can run thousands. A channel passes values between them and makes the receiver wait until a value arrives.
ใส่ go หน้าการเรียกฟังก์ชัน ฟังก์ชันนั้นจะทำงานใน goroutine ไปพร้อมกับส่วนอื่นของโปรแกรม goroutine ใช้ทรัพยากรน้อยมาก เซิร์ฟเวอร์หนึ่งตัวรันได้เป็นพันๆ channel ใช้ส่งค่าระหว่าง goroutine และทำให้ฝั่งรับรอจนกว่าจะมีค่ามาถึง
The three downloads took 600 ms of work but finished in about 300 ms, in the order they completed. When goroutines share a variable, protect it with a sync.Mutex, and use a sync.WaitGroup to wait for all of them:
การดาวน์โหลดสามงานรวมกันใช้เวลาทำงาน 600 ms แต่เสร็จในเวลาประมาณ 300 ms และเรียงตามลำดับที่เสร็จ เมื่อหลาย goroutine ใช้ตัวแปรร่วมกัน ให้ป้องกันด้วย sync.Mutex และใช้ sync.WaitGroup เพื่อรอให้ทุกตัวเสร็จ:
Without the mutex, two goroutines can read and write total at the same moment and lose updates. The result is sometimes wrong, which makes the bug hard to find. go run -race and go test -race detect this for you.ถ้าไม่มี mutex สอง goroutine อาจอ่านและเขียน total ในเวลาเดียวกันจนค่าที่บวกหายไป ผลลัพธ์จะผิดเป็นบางครั้ง ทำให้หาบั๊กยาก go run -race และ go test -race ช่วยตรวจหาปัญหานี้ให้
Lesson 12 · Organising codeบทที่ 12 · จัดระเบียบโค้ด
Packages & modulesPackage และ module
The rest of this guide builds one small program in a real terminal: a task list, then a JSON API for it. A module is the project (go.mod); a package is one folder of .go files. The tasks package keeps the data; main uses it.
ส่วนที่เหลือของคู่มือนี้สร้างโปรแกรมเล็กๆ หนึ่งตัวในเทอร์มินัลจริง เริ่มจากรายการงาน แล้วต่อด้วย JSON API ของมัน module คือตัวโปรเจกต์ (go.mod) ส่วน package คือโฟลเดอร์หนึ่งที่มีไฟล์ .go package tasks เก็บข้อมูล และ main เป็นผู้ใช้
- Import a package by its module path plus folder:
"example.com/taskapi/tasks". Then use it astasks.NewStore().import package ด้วยพาธของ module ต่อด้วยโฟลเดอร์ เช่น"example.com/taskapi/tasks"แล้วเรียกใช้เป็นtasks.NewStore() Store,AddandTaskstart with a capital letter, somaincan use them. The fieldsmu,tasksandnextIDdon't, so only thetaskspackage can touch them.Store,AddและTaskขึ้นต้นด้วยตัวพิมพ์ใหญ่mainจึงใช้ได้ ส่วนฟิลด์mu,tasksและnextIDไม่ใช่ จึงมีแต่ packagetasksที่แตะต้องได้- A comment right above an exported name is its documentation;
go docand editors show it.คอมเมนต์ที่อยู่เหนือชื่อที่ export คือเอกสารของมันgo docและตัวแก้โค้ดจะแสดงให้เห็น
$ go mod init example.com/taskapi go: creating new go.mod: module example.com/taskapi $ go run . error: title is required 1. Learn Go (done: true) 2. Build an API (done: false) $ go vet ./...
go vet printed nothing: it found no suspicious code. ./... means "this package and every package below it".go vet ไม่พิมพ์อะไรเลย แปลว่าไม่พบโค้ดที่น่าสงสัย ./... หมายถึง "package นี้และทุก package ที่อยู่ข้างใต้"
The tools catch mistakes for youเครื่องมือช่วยจับข้อผิดพลาดให้
To see that, I added two bad lines to main.go: one prints a string with %d, the other reads the private field store.tasks.
เพื่อให้เห็นภาพ ผมเพิ่มบรรทัดที่ผิดสองบรรทัดใน main.go บรรทัดแรกพิมพ์ string ด้วย %d อีกบรรทัดอ่านฟิลด์ส่วนตัว store.tasks
$ go build ./... # example.com/taskapi ./main.go:18:20: store.tasks undefined (cannot refer to unexported field tasks) $ go vet ./... # after removing the store.tasks line # example.com/taskapi # [example.com/taskapi] ./main.go:17:14: fmt.Printf format %d has arg "three" of wrong type string
Go also has one official code style, applied by gofmt (or go fmt). Nobody argues about tabs or brace position; most editors run it every time you save.
Go มีรูปแบบการจัดโค้ดอย่างเป็นทางการแบบเดียว ซึ่ง gofmt (หรือ go fmt) จัดให้ จึงไม่มีใครต้องเถียงเรื่องแท็บหรือตำแหน่งวงเล็บ ตัวแก้โค้ดส่วนใหญ่รันให้ทุกครั้งที่บันทึก
$ gofmt -l . main.go $ gofmt -d main.go diff main.go.orig main.go --- main.go.orig +++ main.go @@ -1,5 +1,7 @@ package main + import "fmt" -func main(){ -fmt.Println("hi") - } + +func main() { + fmt.Println("hi") +}
-l lists files that need formatting, -d shows the changes, and -w writes them.-l แสดงไฟล์ที่ต้องจัดรูปแบบ -d แสดงสิ่งที่จะเปลี่ยน และ -w เขียนการเปลี่ยนแปลงลงไฟล์
Lesson 13 · The webบทที่ 13 · เว็บ
A JSON web serverเว็บเซิร์ฟเวอร์ JSON
Go's standard library includes a production-ready web server, net/http. No framework needed. Replace main.go with a small JSON API around the same tasks package:
ไลบรารีมาตรฐานของ Go มีเว็บเซิร์ฟเวอร์ที่พร้อมใช้งานจริงอยู่แล้ว คือ net/http ไม่ต้องใช้เฟรมเวิร์ก แทนที่ main.go ด้วย JSON API เล็กๆ ที่ใช้ package tasks ตัวเดิม:
"GET /tasks"and"PATCH /tasks/{id}/done"are route patterns with a method, built into Go since 1.22.r.PathValue("id")reads the{id}part."GET /tasks"และ"PATCH /tasks/{id}/done"คือรูปแบบ route ที่ระบุ method ได้ ซึ่งมีในตัว Go ตั้งแต่ 1.22r.PathValue("id")ใช้อ่านส่วน{id}- The tags on
Task(`json:"title"`) choose the JSON names.json.NewDecoder(r.Body).Decode(&body)reads the request;json.NewEncoder(w).Encode(v)writes the response.tag บนTask(`json:"title"`) กำหนดชื่อใน JSON ส่วนjson.NewDecoder(r.Body).Decode(&body)อ่านคำขอ และjson.NewEncoder(w).Encode(v)เขียนคำตอบ - Each request runs in its own goroutine, so several can hit
Storeat once. That's whyStoreuses async.Mutex(lesson 11).แต่ละคำขอทำงานใน goroutine ของตัวเอง หลายคำขอจึงอาจเข้าถึงStoreพร้อมกัน นี่คือเหตุผลที่Storeใช้sync.Mutex(บทที่ 11)
$ go build -o taskapi . && ./taskapi 2026/10/05 23:23:35 listening on http://localhost:8080
$ curl -s localhost:8080/tasks [] $ curl -si -X POST localhost:8080/tasks -d '{"title":"Learn Go"}' HTTP/1.1 201 Created Content-Type: application/json {"id":1,"title":"Learn Go","done":false} $ curl -s -X POST localhost:8080/tasks -d '{"title":" Build an API "}' {"id":2,"title":"Build an API","done":false} $ curl -s -w "%{http_code}\n" -X POST localhost:8080/tasks -d '{"title":" "}' {"error":"title is required"} 422 $ curl -s -w "%{http_code}\n" -X POST localhost:8080/tasks -d '{"title":' {"error":"invalid JSON"} 400 $ curl -s -X PATCH localhost:8080/tasks/1/done {"id":1,"title":"Learn Go","done":true} $ curl -s -w "%{http_code}\n" -X PATCH localhost:8080/tasks/99/done {"error":"task not found"} 404 $ curl -s -w "%{http_code}\n" -X DELETE localhost:8080/tasks Method Not Allowed 405 $ curl -s localhost:8080/tasks [{"id":1,"title":"Learn Go","done":true},{"id":2,"title":"Build an API","done":false}]
Requests also sent -H "Content-Type: application/json", and the date and length headers are left out of the -i output. Note the 422 for a title of only spaces, the 400 for broken JSON, and the 405 Go returns by itself for a method no route handles.คำขอส่ง -H "Content-Type: application/json" ไปด้วย และส่วนหัววันที่กับความยาวถูกตัดออกจากผลลัพธ์ของ -i สังเกตว่าได้ 422 เมื่อชื่องานมีแค่ช่องว่าง ได้ 400 เมื่อ JSON เสีย และ Go ตอบ 405 ให้เองเมื่อไม่มี route ใดรับ method นั้น
Lesson 14 · Confidenceบทที่ 14 · ความมั่นใจ
Testingการทดสอบ
Testing is built into Go: no library to install. Tests live next to the code in files ending in _test.go, and go test runs them. Go code usually tests with a table: a list of inputs and expected results, checked in one loop. Here's the idea in a runnable form. Delete the TrimSpace line and press Run.
การทดสอบมีมาในตัว Go ไม่ต้องติดตั้งไลบรารีเพิ่ม เทสต์อยู่ข้างๆ โค้ดในไฟล์ที่ลงท้ายด้วย _test.go และ go test เป็นตัวรัน โค้ด Go มักทดสอบด้วยตาราง คือรายการข้อมูลเข้าและผลลัพธ์ที่คาดไว้ แล้วตรวจในลูปเดียว นี่คือแนวคิดในแบบที่รันได้ ลองลบบรรทัด TrimSpace แล้วกด Run
The real tests for the task API: a table-driven test for CleanTitle, and two tests that call the HTTP handler directly with httptest, with no server or network.
เทสต์จริงของ task API ได้แก่เทสต์แบบตารางสำหรับ CleanTitle และเทสต์สองตัวที่เรียก HTTP handler โดยตรงด้วย httptest ไม่ต้องมีเซิร์ฟเวอร์หรือเครือข่าย
Red: a planted bugแดง: บั๊กที่ตั้งใจใส่ไว้
To show a failure, I deleted the strings.TrimSpace line from CleanTitle. Three checks catch it, in both packages:
เพื่อให้เห็นความล้มเหลว ผมลบบรรทัด strings.TrimSpace ออกจาก CleanTitle มีการตรวจสามจุดที่จับได้ ในทั้งสอง package:
$ go test ./... --- FAIL: TestBlankTitleIsRejected (0.00s) main_test.go:35: status 201, want 422 FAIL FAIL example.com/taskapi 1.212s --- FAIL: TestCleanTitle (0.00s) --- FAIL: TestCleanTitle/trims_spaces (0.00s) tasks_test.go:28: CleanTitle(" Write tests ") = " Write tests ", want "Write tests" --- FAIL: TestCleanTitle/only_spaces (0.00s) tasks_test.go:25: CleanTitle(" ") error = <nil>, want title is required FAIL FAIL example.com/taskapi/tasks 0.653s FAIL
Green: put the line backเขียว: ใส่บรรทัดนั้นกลับคืน
$ go test ./... ok example.com/taskapi 0.519s ok example.com/taskapi/tasks 1.051s $ go test -v ./tasks === RUN TestCleanTitle === RUN TestCleanTitle/plain_title === RUN TestCleanTitle/trims_spaces === RUN TestCleanTitle/empty === RUN TestCleanTitle/only_spaces --- PASS: TestCleanTitle (0.00s) --- PASS: TestCleanTitle/plain_title (0.00s) --- PASS: TestCleanTitle/trims_spaces (0.00s) --- PASS: TestCleanTitle/empty (0.00s) --- PASS: TestCleanTitle/only_spaces (0.00s) === RUN TestMarkDone --- PASS: TestMarkDone (0.00s) PASS ok example.com/taskapi/tasks 0.300s $ go test -cover ./... ok example.com/taskapi 0.577s coverage: 53.3% of statements ok example.com/taskapi/tasks 1.112s coverage: 83.3% of statements $ go test -run 'TestCleanTitle/only' -v ./tasks === RUN TestCleanTitle === RUN TestCleanTitle/only_spaces --- PASS: TestCleanTitle (0.00s) --- PASS: TestCleanTitle/only_spaces (0.00s) PASS ok example.com/taskapi/tasks 0.323s
-v lists every test and sub-test, -cover shows how much of the code the tests ran, and -run picks tests by name.-v แสดงทุกเทสต์และเทสต์ย่อย -cover แสดงว่าเทสต์รันโค้ดไปกี่เปอร์เซ็นต์ และ -run เลือกเทสต์ตามชื่อ
Lesson 15 · Your turnบทที่ 15 · ถึงตาคุณแล้ว
Practiceแบบฝึกหัด
Write the code, press Run, and compare with the solution when you're done. Every solution was run with go run, and its output is shown under it.
เขียนโค้ด กด Run แล้วเทียบกับเฉลยเมื่อเสร็จ ทุกเฉลยถูกรันด้วย go run และแสดงผลลัพธ์ไว้ด้านล่าง
1. Total of the even numbers1. ผลรวมของเลขคู่
Add up only the even numbers. n%2 == 0 is true for even numbers.รวมเฉพาะเลขคู่ n%2 == 0 เป็นจริงเมื่อ n เป็นเลขคู่
2. Count the words2. นับคำ
Count how often each word appears, using a map[string]int and strings.Fields.นับว่าแต่ละคำปรากฏกี่ครั้ง โดยใช้ map[string]int และ strings.Fields
3. FizzBuzz3. FizzBuzz
For 1 to 15, print Fizz for multiples of 3, Buzz for multiples of 5, FizzBuzz for both, and the number otherwise. A switch with no value fits well.สำหรับ 1 ถึง 15 ให้พิมพ์ Fizz เมื่อหารด้วย 3 ลงตัว Buzz เมื่อหารด้วย 5 ลงตัว FizzBuzz เมื่อหารลงตัวทั้งคู่ และพิมพ์ตัวเลขในกรณีอื่น switch ที่ไม่มีค่าใช้ได้ดีมาก
4. Reverse text, Thai included4. กลับข้อความ รวมถึงภาษาไทย
Reverse "Hello โลก" so it prints กลโ olleH. Reversing bytes would break the Thai letters; reverse runes instead.กลับข้อความ "Hello โลก" ให้พิมพ์เป็น กลโ olleH ถ้ากลับเป็นไบต์ ตัวอักษรไทยจะเสีย ให้กลับเป็น rune แทน
5. Add up in parallel5. บวกเลขแบบขนาน
Split the slice in two, add each half in its own goroutine, send both sums over a channel, and print the total.แบ่ง slice เป็นสองครึ่ง ให้แต่ละครึ่งบวกกันใน goroutine ของตัวเอง ส่งผลรวมทั้งสองผ่าน channel แล้วพิมพ์ยอดรวม
Lesson 16 · Debuggingบทที่ 16 · การดีบัก
Common mistakesข้อผิดพลาดที่พบบ่อย
The comments show what the real Go compiler and runtime printed (go run, Go 1.25.4). Several of these are compile errors, which the browser runner doesn't always report, so learn the messages here.
คอมเมนต์แสดงสิ่งที่คอมไพเลอร์และ runtime ของ Go ตัวจริงพิมพ์ออกมา (go run, Go 1.25.4) หลายข้อเป็น compile error ซึ่งตัวรันในเบราว์เซอร์ไม่ได้แจ้งทุกครั้ง จึงควรจำข้อความจากที่นี่
An unused variable or importตัวแปรหรือ import ที่ไม่ได้ใช้
Go refuses to compile code that declares something and never uses it. It feels strict at first, but it keeps dead code out. Use it, delete it, or assign it to _.Go ไม่ยอมคอมไพล์โค้ดที่ประกาศอะไรไว้แล้วไม่ได้ใช้ ตอนแรกอาจรู้สึกว่าเข้มงวด แต่ช่วยกันไม่ให้มีโค้ดที่ไม่ได้ใช้ค้างอยู่ ให้ใช้มัน ลบทิ้ง หรือกำหนดให้ _
:= outside a functionใช้ := นอกฟังก์ชัน
:= only works inside functions. At package level, use var.:= ใช้ได้เฉพาะในฟังก์ชัน ถ้าอยู่ระดับ package ให้ใช้ var
Writing to a nil mapเขียนลง map ที่เป็น nil
var m map[string]int is nil: you can read from it, but writing panics. Create it with map[string]int{} or make.var m map[string]int เป็น nil อ่านได้ แต่ถ้าเขียนจะ panic ให้สร้างด้วย map[string]int{} หรือ make
A value receiver that should change the structvalue receiver ที่ควรแก้ไข struct
A value receiver gets a copy, so the change is lost. If a method modifies its struct, give it a pointer receiver.value receiver ได้รับสำเนา การแก้ไขจึงหายไป ถ้า method ต้องแก้ struct ของตัวเอง ให้ใช้ pointer receiver
Ignoring an error with _ทิ้ง error ด้วย _
When a call fails, the other results are usually zero values. Ignore the error and you carry on with wrong data, silently.เมื่อการเรียกล้มเหลว ค่าอื่นที่คืนมามักเป็นค่าศูนย์ ถ้าทิ้ง error ไป โปรแกรมจะทำงานต่อด้วยข้อมูลที่ผิดโดยไม่มีใครรู้
Index out of rangeตำแหน่งเกินขอบเขต
Indexes run from 0 to len-1. Go checks every index and panics instead of reading random memory. The message says the index and the length.ตำแหน่งเริ่มจาก 0 ถึง len-1 Go ตรวจทุกครั้งและจะ panic แทนการอ่านหน่วยความจำมั่วๆ ข้อความบอกทั้งตำแหน่งและความยาว
Lesson 17 · Referenceบทที่ 17 · อ้างอิง
Glossaryคำศัพท์
The English terms are what you'll see in Go's documentation and error messages, so it pays to know both. คำศัพท์ภาษาอังกฤษคือสิ่งที่จะเจอในเอกสารและข้อความแจ้งข้อผิดพลาดของ Go จึงควรรู้ทั้งสองภาษา
| English | ไทย | Meaningความหมาย |
|---|---|---|
| module | โมดูล | A project, defined by go.modโปรเจกต์หนึ่งตัว กำหนดด้วย go.mod |
| package | แพ็กเกจ | One folder of Go files that belong togetherโฟลเดอร์หนึ่งที่มีไฟล์ Go ที่อยู่ด้วยกัน |
| exported | ส่งออก (exported) | A name starting with a capital letter, usable from other packagesชื่อที่ขึ้นต้นด้วยตัวพิมพ์ใหญ่ ใช้จาก package อื่นได้ |
| zero value | ค่าศูนย์ | The value a variable has before you set it: 0, "", false, nilค่าที่ตัวแปรมีก่อนกำหนดค่า: 0, "", false, nil |
| slice | สไลซ์ | A list that can grow, written []Tรายการที่ขยายได้ เขียนว่า []T |
| map | แมป | Key–value lookup, written map[K]Vการค้นหาแบบคีย์–ค่า เขียนว่า map[K]V |
| rune | รูน (rune) | One Unicode characterอักขระ Unicode หนึ่งตัว |
| struct | สตรักต์ | A type that groups named fieldsชนิดข้อมูลที่รวมฟิลด์ที่มีชื่อเข้าด้วยกัน |
| method / receiver | เมธอด / รีซีฟเวอร์ | A function attached to a type / the value it's called onฟังก์ชันที่ผูกกับชนิดข้อมูล / ค่าที่ method ถูกเรียกใช้ |
| pointer | พอยน์เตอร์ | The address of a value; &x makes one, *T is its typeที่อยู่ของค่า &x ใช้สร้าง และ *T คือชนิดของมัน |
| interface | อินเทอร์เฟซ | A set of methods; any type with them satisfies itชุดของ method ชนิดใดที่มี method ครบก็เป็น interface นั้น |
| error | ข้อผิดพลาด (error) | A value describing a failure, returned as the last resultค่าที่บอกความล้มเหลว คืนเป็นค่าสุดท้าย |
| panic | แพนิก | An unrecoverable stop, usually from a bugการหยุดทำงานที่กู้คืนไม่ได้ มักเกิดจากบั๊ก |
| defer | defer | Run this call when the function returnsให้เรียกคำสั่งนี้ตอนที่ฟังก์ชันจบ |
| goroutine | กอรูทีน | A function running alongside the rest of the programฟังก์ชันที่ทำงานไปพร้อมกับส่วนอื่นของโปรแกรม |
| channel | แชนเนล | A pipe for passing values between goroutinesท่อส่งค่าระหว่าง goroutine |
| mutex | มิวเท็กซ์ | A lock so only one goroutine uses shared data at a timeกุญแจที่ทำให้มีเพียง goroutine เดียวใช้ข้อมูลร่วมได้ในแต่ละครั้ง |
| table-driven test | เทสต์แบบตาราง | A test that loops over a list of inputs and expected resultsเทสต์ที่วนผ่านรายการข้อมูลเข้าและผลลัพธ์ที่คาดไว้ |