1 · สามวิธีประกาศตัวแปร
// 1) var + type — ไม่ใส่ค่า ได้ zero value
var i int // i = 0
// 2) var + ค่าเริ่มต้น — เขียน type ไว้ก็ได้ หรือละไว้ให้ compiler เดาจากค่าก็ได้
var j int = 2 // เขียน type ไว้ชัด ๆ
var c, python, java = true, false, "no!" // ละ type — compiler เดาให้เป็น bool, bool, string
// 3) short declaration — สั้นสุด ใช้บ่อยสุด
k := 3
name, age := "Alice", 30
:= ใช้ได้เฉพาะข้างในฟังก์ชัน — นอกฟังก์ชัน
(ระดับ package) ต้องใช้ var เท่านั้น
เหตุผลคือทุกบรรทัดที่อยู่นอกฟังก์ชันต้องขึ้นต้นด้วย keyword
(คำสงวนที่ภาษาจองไว้ เอาไปตั้งเป็นชื่อตัวแปรไม่ได้ — Go มีทั้งหมด 25 คำ)
และ keyword ที่ขึ้นต้นบรรทัดระดับ package ได้มีแค่ 6 คำ:
package, import, func, var,
const, type — และ := ไม่ใช่ keyword
| สถานการณ์ | ใช้อะไร |
|---|---|
| ในฟังก์ชัน มีค่าเริ่มต้นอยู่แล้ว | := — สำนวนมาตรฐาน |
| ต้องการ zero value (ค่าเริ่มต้นที่ Go เติมให้เอง — หัวข้อ 2) | var x int |
| นอกฟังก์ชัน (package level) | var เท่านั้น |
| อยากบังคับ type ให้ชัด | var x float64 = 3 |
- keyword
- คำสงวนที่ภาษาจองไว้ เอาไปตั้งเป็นชื่อตัวแปรไม่ได้ · Go มี 25 คำ
(
break,func,if,for,varฯลฯ) ซึ่งถือว่าน้อยมากเมื่อเทียบกับภาษาอื่น — ประโยคที่เอาไปพูดได้เลยคือ “Go มี keyword แค่ 25 คำ” - package level
- “ตำแหน่งที่อยู่นอกฟังก์ชัน” · เวลาอ่าน error หรือเอกสารจะเจอคำนี้บ่อย เช่น “ตัวแปรตัวนี้ประกาศไว้ที่ package level” = ประกาศไว้นอกฟังก์ชัน ทุกฟังก์ชันในแพ็กเกจเดียวกันเห็นหมด
- short variable declaration (
:=) - ชื่อทางการของ
:=· ใช้ได้เฉพาะในฟังก์ชัน · ถ้าเผลอเขียนนอกฟังก์ชันจะเจอ error ว่าsyntax error: non-declaration statement outside function body— เจอข้อความนี้เมื่อไหร่ให้นึกถึงคำนี้ทันที
2 · Zero value — Go ไม่มีตัวแปร "ไม่มีค่า"
ประกาศแล้วไม่ใส่ค่า Go จะเติมค่าให้เสมอ — ไม่มีคำว่า undefined
| Type | Zero value |
|---|---|
int, float64 และตัวเลขทุกชนิด | 0 |
bool | false |
string | "" (สตริงว่าง ไม่ใช่ null) |
| pointer, slice, map, func, chan, interface (ยังไม่ต้องรู้ว่าคืออะไร จะเจอตัวจริงในบทหลัง ๆ) | nil — คำที่ Go ใช้แทน "ยังว่าง ยังไม่ได้ชี้ไปที่อะไร" คล้าย null ในภาษาอื่น |
ตัวอย่างข้างล่างใช้ fmt.Printf ซึ่งต่างจาก fmt.Println ที่เคยเห็นในบทที่ 1 —
Printf ต้องส่ง "สตริงรูปแบบ" เข้าไปเป็นตัวแรก แล้วเอาค่าที่ตามมาไปเสียบแทนตำแหน่งที่
ขึ้นต้นด้วย % เรียงตามลำดับ ตอนนี้รู้แค่ 2 ตัวพอ: %v = พิมพ์ค่านั้นแบบปกติ,
%q = พิมพ์สตริงพร้อมเครื่องหมายคำพูดครอบ (จะได้เห็นชัดว่าสตริงว่างหน้าตาเป็นยังไง)
ส่วน \n คือสั่งขึ้นบรรทัดใหม่ — รายการ % ทั้งหมดอยู่ในหัวข้อ 4
var i int; var f float64; var b bool; var s string
fmt.Printf("%v %v %v %q\n", i, f, b, s)
// 0 0 false ""
ทำไมเรื่องนี้สำคัญ: ในภาษาอื่น "ตัวแปรยังไม่ได้เซ็ต" กับ "ตัวแปรเป็นศูนย์" ต่างกัน แต่ Go ยุบให้เหลืออันเดียว — ตัวแปรพร้อมใช้เสมอ ไม่ต้องเช็ค null ก่อน แลกกับที่คุณต้องระวังว่า "0" อาจแปลว่า "ยังไม่ได้ตั้งค่า" ก็ได้
ร้านอาหารบางร้านวางแก้วเปล่าไว้ที่โต๊ะตั้งแต่ก่อนเรานั่ง
อยากดื่มน้ำก็รินได้เลย ไม่ต้องเรียกพนักงานมาเอาแก้วให้ก่อน
อีกร้านไม่วางอะไรไว้เลย — ต้องเช็คทุกครั้งว่าตรงหน้ามีแก้วหรือยัง
ถ้าลืมเช็คแล้วรินเลย น้ำก็หกเลอะโต๊ะ
Go เป็นร้านแบบแรก: ประกาศตัวแปรปุ๊บ มีค่าให้ใช้ทันที
ส่วนภาษาที่มี null หรือ undefined เป็นร้านแบบหลัง —
ต้องเช็คก่อนใช้ ไม่งั้นโปรแกรมพัง
ที่ไม่เหมือนกัน: แก้วเปล่ากับแก้วที่คนดื่มหมดพอดี หน้าตาเหมือนกันเป๊ะ ·
ตัวแปรก็เหมือนกัน เห็นเลข 0 แล้วบอกไม่ได้ว่า
"ยังไม่มีใครใส่ค่า" หรือ "ใส่ค่าเป็นศูนย์มาจริง ๆ"
ตรงนี้เป็นเรื่องที่เราต้องออกแบบเองว่าจะแยกยังไง
และไม่ใช่ทุกแก้วจะรินได้เลย — pointer, slice, map ฯลฯ มี zero value
เป็น nil ซึ่งเท่ากับ "ยังไม่มีแก้ว" เขียนลง map ที่เป็น nil จะพังทันที
(panic: assignment to entry in nil map) ·
กลุ่มนี้ยังต้องเช็คก่อนใช้อยู่ ที่ไม่ต้องเช็คเลยคือตัวเลข สตริง และ bool
- zero value
- “ค่าที่ Go เติมให้เองตอนประกาศ” · เวลาถามคนอื่นให้พูดว่า “zero value ของ type นี้คืออะไร” จะได้คำตอบตรงกว่าถามว่า “ตัวแปรนี้เริ่มที่เท่าไหร่”
- nil
- คำที่ Go ใช้แทน “ยังว่าง ยังไม่ได้ชี้ไปที่อะไร” · ประโยคที่จะได้ยินบ่อยคือ
“ตัวนี้เป็น nil อยู่” = ยังไม่มีของจริงอยู่ข้างใน ·
ระวังไว้ว่า
int,string,boolเป็น nil ไม่ได้เลย - nil check
- การเช็คก่อนใช้ว่ามีของจริงไหม — เขียนว่า
if x != nil· ข้อดีของ zero value คือ ตัวเลข สตริง และ bool ไม่ต้อง nil check เลย ประโยคนี้เอาไปพูดกับ senior ได้ตรง ๆ
3 · จุดที่คนใหม่ติดกันทุกคน: Go ไม่แปลง type ให้
var i int = 42
var f float64 = 1.5
result := i + f
โค้ดนี้เป็นยังไง?
compile ไม่ผ่าน:
invalid operation: i + f (mismatched types int and float64)
ในภาษาอย่าง Python หรือ JavaScript อันนี้ผ่านสบาย ๆ แต่ Go บังคับให้
คุณเขียนออกมาเองว่าจะแปลงยังไง ต้องเขียน
float64(i) + f
รูปแบบการแปลงคือ T(v) — เอา type มาครอบค่า:
i := 42
f := float64(i) // int → float64
u := uint(f) // float64 → uint
// ใช้จริง — math.Sqrt รับ float64 เท่านั้น
var x, y int = 3, 4
var dist float64 = math.Sqrt(float64(x*x + y*y))
f := 3.9
i := int(f) // 3 — ตัดทิ้ง ไม่ใช่ปัดเศษ!
big := 300
b := uint8(big) // 44 — uint8 เก็บได้แค่ 0–255 ล้นแล้ววนกลับ
การแปลง type ไม่มีการเตือน ถ้าค่าไม่พอดี
มีแบงก์ไทยอยู่ในกระเป๋าซ้าย มีเงินเยนอยู่กระเป๋าขวา อยากรู้ว่ารวมกันได้เท่าไหร่
เทกองรวมกันแล้วนับเลยไม่ได้ — ต้องเดินไปบูธแลกเงินก่อน
ให้ทั้งสองกองอยู่ในสกุลเดียวกัน แล้วค่อยบวก
int กับ float64 ก็คนละสกุลกัน ·
float64(i) คือการเดินไปบูธ — พูดออกมาชัด ๆ ว่าจะแปลงตัวไหนเป็นอะไร
Go ไม่มีบูธอัตโนมัติที่แลกให้เงียบ ๆ แบบ Python หรือ JavaScript
เราต้องเขียนสั่งเอง — กฎนี้ใช้กับค่าที่อยู่ในตัวแปร
ส่วนค่าคงที่ที่เขียนตรง ๆ Go ยอมให้เอง เช่น var x float64 = 3
(ดูคำว่า untyped constant ข้างล่าง)
ที่ไม่เหมือนกัน: บูธแลกเงินจริงเปลี่ยนตัวเลขบนแบงก์ตามอัตราแลกเปลี่ยน
แต่ float64(42) ยังเป็น 42 เท่าเดิม เปลี่ยนแค่ "ชนิด" ที่ Go มองเห็น ·
ค่าจะเพี้ยนก็ต่อเมื่อปลายทางเก็บไม่ไหวเท่านั้น เช่น f := 3.9
แล้วแปลง int(f) จะได้ 3 เพราะ int ไม่มีที่ให้เก็บทศนิยม
// ผ่านตัวแปร → รันได้ ตัดค่าเงียบ ๆ
f := 3.9; fmt.Println(int(f)) // 3 ✓ รันได้
big := 300; fmt.Println(uint8(big)) // 44 ✓ รันได้
// ใส่ค่าคงที่ตรง ๆ → compile ไม่ผ่าน!
fmt.Println(int(3.9)) // ✗ cannot convert 3.9 (untyped float constant) to type int
fmt.Println(uint8(300)) // ✗ constant 300 overflows uint8
เพราะ ค่าคงที่ (constant) Go รู้ค่าตั้งแต่ตอน compile เลยตรวจได้เลยว่า ข้อมูลจะหาย — แต่ค่าในตัวแปรรู้ตอน runtime เท่านั้น จึงได้แค่ปล่อยผ่าน นี่คือเหตุผลที่ต้องระวังตัวแปร มากกว่าค่าคงที่
- type conversion
- การแปลงชนิดที่เราเขียนสั่งเอง =
T(v)· เวลาติดให้ถามว่า “ตรงนี้ต้อง convert เป็น float64 ก่อนไหม” แทนที่จะถามว่า “ทำไมมันบวกกันไม่ได้” — จะได้คำตอบเร็วกว่ามาก - implicit / explicit conversion
- implicit = ภาษาแปลงให้เงียบ ๆ (Python, JavaScript) · explicit = เราต้องเขียนเอง (Go) · ประโยคที่เอาไปใช้ได้เลย: “Go ไม่มี implicit conversion” ประโยคเดียวนี้อธิบายหัวข้อนี้ได้ทั้งหัวข้อ
- mismatched types
- ข้อความ error ที่แปลว่า “สองข้างคนละชนิด” · เอาไปค้นหรือถาม AI ได้ตรง ๆ ว่า “invalid operation: mismatched types int and float64 แก้ยังไง” ดีกว่าพิมพ์ว่า “โค้ด Go บวกเลขไม่ได้”
- overflow
- “ใส่ค่าเกินที่ภาชนะรับไหว แล้ววนกลับ” เช่น
big := 300แล้วแปลงuint8(big)จะได้44· เวลาสงสัยว่าตัวเลขจะล้นไหม ให้ถามว่า “ตรงนี้มีโอกาส overflow ไหม” - untyped constant
- ค่าคงที่ที่เขียนลงไปตรง ๆ อย่าง
3.9หรือ300ซึ่ง ยังไม่มีชนิดจนกว่าจะถูกเอาไปใช้ · นี่คือเหตุผลที่ Go จับint(3.9)ได้ตั้งแต่ตอนแปลโค้ด แต่จับint(f)ไม่ได้ - compile time / runtime
- compile time = ตอนแปลโค้ด ยังไม่ทันรัน · runtime = ตอนโปรแกรมทำงานจริง · “พังตอน compile” ดีกว่า “พังตอน runtime” เสมอ เพราะยังไม่ทันถึงมือผู้ใช้
4 · Type inference — compiler เดา type ให้ยังไง
n := 42
f := 3.142
s := "hello"
b := true
fmt.Printf("%T %T %T %T\n", n, f, s, b)
พิมพ์ type อะไรออกมาบ้าง?
int float64 string bool
สังเกตว่า 3.142 ได้ float64 ไม่ใช่
float32 และ 42 ได้ int
ไม่ใช่ int64 — นี่คือ default type ของค่าคงที่ที่ยังไม่ระบุชนิด
%T คือตัวช่วยที่พิมพ์ type ออกมา — เครื่องมือดีบักที่ดีที่สุด
ตอนงงว่าตัวแปรเป็น type อะไร
- format verb
- โค้ดสั้น ๆ ที่ขึ้นต้นด้วย
%ใช้บอกPrintfว่าจะพิมพ์ค่านั้นออกมาหน้าตาแบบไหน เช่น%v,%T· ตารางข้างล่างคือชุดที่ใช้บ่อยที่สุด - type inference
- “compiler เดา type จากค่าที่เราให้มา” — คือสิ่งที่เกิดขึ้นตอนเขียน
n := 42· เวลาถาม senior ให้พูดว่า “ตัวนี้ inference ออกมาเป็น type อะไร” จะสื่อกว่าถามว่า “ตัวนี้เป็นเลขแบบไหน” - default type
- ชนิดที่ค่าคงที่จะกลายเป็นถ้าเราไม่ระบุ
(เลขจำนวนเต็ม →
int, เลขทศนิยม →float64) · นี่คือเหตุผลที่f := 3.142ได้float64ไม่ใช่float32
| verb | พิมพ์อะไร | ตัวอย่างผลลัพธ์ |
|---|---|---|
%v | ค่าแบบ default — ใช้ได้กับทุก type | 42 / hi / true |
%T | type ของค่านั้น | int / string / float64 |
%d / %s / %t | เลขจำนวนเต็ม / สตริง / bool | 42 / hi / true |
%q | สตริงพร้อมเครื่องหมายคำพูด | "hi" |
%.2f | ทศนิยม 2 ตำแหน่ง | 2500.00 |
%+v | ค่า + ชื่อ field (ใช้กับ struct — เรียนบทหลัง) | {Name:Alice Age:30} |
5 · เลือก type ตัวเลขยังไง
ใช้ int กับ float64 ไปเลย
จนกว่าจะมีเหตุผลเฉพาะที่ต้องใช้อย่างอื่น
แล้วเหตุผลเฉพาะคืออะไรบ้าง:
| Type | ช่วงค่า | ใช้ตอน |
|---|---|---|
int8 | −128 ถึง 127 | protocol, binary data, ประหยัด memory |
int32 | ±2.1 พันล้าน | field ขนาดคงที่, Unicode rune |
int64 | ±9.22e18 | timestamp, database ID, ขนาดไฟล์ |
uint8 (byte) | 0 ถึง 255 | ข้อมูล byte, ช่องสี, raw binary |
rune | = int32 | ตัวอักษร 1 ตัว (สำคัญมากกับภาษาไทย) |
s := "สวัสดี"
len(s) // 18 — นับเป็น byte!
len([]rune(s)) // 6 — นับเป็น rune ✓
[]rune(s) อ่านว่า "แปลงสตริง s เป็นลิสต์ของ rune" —
เครื่องหมาย [] ที่นำหน้า type แปลว่า "ลิสต์ของสิ่งนั้น" (ชื่อจริงคือ slice จะเรียนเต็ม ๆ ในบทเรื่อง slice)
พอกลายเป็นลิสต์ของ rune แล้ว len ก็นับจำนวนสมาชิกในลิสต์ แทนที่จะนับ byte
ตัวอักษรไทยตัวหนึ่งกิน 3 bytes ใน UTF-8 → len เลยได้ 18 ไม่ใช่ 6
แต่ระวังคำว่า "6" ให้ดี — มันคือจำนวน rune ไม่ใช่จำนวนตัวที่ตามองเห็น:
ส · ว · ◌ั · ส · ด · ◌ี คือ 6 rune เพราะสระและวรรณยุกต์นับเป็น rune ของตัวเอง
ทั้งที่เขียนซ้อนอยู่บนพยัญชนะ
สรุป: ถ้าจะนับ "ตัวอักษร" ให้ใกล้เคียงความจริง ต้องแปลงเป็น []rune ก่อนเสมอ
ส่วนการนับ "ตัวที่ตามองเห็น" ของภาษาไทยยังต้องใช้วิธีอื่นอีก ไว้พูดถึงในบทเรื่อง string
ลองนึกถึงตู้ล็อกเกอร์ที่ทุกช่องขนาดเท่ากันหมด
ของชิ้นเล็กใส่ช่องเดียวจบ แต่ของชิ้นใหญ่ต้องจองติดกัน 3 ช่องถึงจะใส่ได้
พอถามว่า "ใช้ไปเท่าไหร่" คำตอบจะได้คนละเลข ขึ้นกับว่านับอะไร:
นับช่องที่ใช้ กับนับจำนวนของ
len(s) คือการนับ "ช่อง" (byte) ·
len([]rune(s)) คือการนับ "ชิ้นของ" (rune)
ตัวอักษรอังกฤษเป็นของชิ้นเล็ก 1 ช่องจบ · ตัวอักษรไทยเป็นของชิ้นใหญ่ กิน 3 ช่อง
→ "สวัสดี" จึงใช้ไป 18 ช่อง ทั้งที่มีของอยู่ 6 ชิ้น
ที่ไม่เหมือนกัน: ของในล็อกเกอร์คือ "1 ชิ้นที่ตามองเห็น" แต่ rune ไม่ใช่ —
สระกับวรรณยุกต์ที่ลอยอยู่บนพยัญชนะนับเป็นชิ้นแยกของมันเอง
"สวัสดี" จึงเป็น 6 rune ทั้งที่ตาเห็นเป็น 4 ตัว
(ส · วั · ส · ดี)
- byte
- “1 ช่องเก็บ” — หน่วยเล็กสุดที่
lenของ string นับให้ · ใน Go คำว่าbyteเป็นแค่ชื่อเล่นของuint8 - rune
- “Unicode code point 1 ตัว” — คำว่า code point
คือศัพท์ทางการ ใช้คำนี้เวลาคุยกับ senior หรือค้นเอกสาร ·
ใน Go เป็นชื่อเล่นของ
int32· ระวังว่า 1 code point ยังไม่เท่ากับ 1 ตัวที่ตามองเห็น (อันนั้นคือ grapheme cluster ข้างล่าง) · เวลาถามให้พูดว่า “ตรงนี้นับเป็น byte หรือ rune” จะสื่อกว่าถามว่า “ทำไมมันนับตัวอักษรผิด” - UTF-8 (encoding)
- วิธีเข้ารหัสที่กำหนดว่าตัวอักษรแต่ละตัวจะกินกี่ byte — อังกฤษ 1 byte ส่วนไทยส่วนใหญ่ 3 bytes · string literal ที่เราพิมพ์ลงในโค้ด Go เป็น UTF-8 เสมอ ส่วนตัว string เองคือลำดับ byte อะไรก็ได้ (เช่น byte ดิบที่อ่านมาจากไฟล์ อาจไม่ใช่ UTF-8 ที่ถูกต้อง) แต่โดยธรรมเนียมแล้วเราเก็บเป็น UTF-8
- grapheme cluster
- “ตัวที่ตามองเห็น 1 ตัว” ซึ่งอาจประกอบจากหลาย rune (พยัญชนะ + สระ + วรรณยุกต์) ·
ถ้าวันไหนต้องนับตัวอักษรไทยให้ตรงกับที่คนเห็น คำที่ต้องเอาไปค้นคือคำนี้
ไม่ใช่
rune
6 · ทดสอบความจำ
1. เขียน count := 0 ไว้นอกฟังก์ชัน (ระดับ package) จะเป็นยังไง?
syntax error: non-declaration statement outside function body —
:= ใช้ได้เฉพาะในฟังก์ชัน นอกฟังก์ชันทุกบรรทัดต้องขึ้นต้นด้วย keyword
2. var s string แล้วยังไม่ใส่ค่า — s มีค่าอะไร?
zero value ของ string คือ "" —
ไม่ใช่ nil (string ใน Go เป็น nil ไม่ได้เลย)
ใช้ได้ทันทีไม่ต้องเช็คก่อน
3. i เป็น int, f เป็น float64 — เขียนยังไงถึงบวกกันได้?
Go ใช้รูปแบบ T(v) — เอา type ครอบค่า ไม่ใช่แบบ C
((float64) i) และไม่ใช่ type assertion (i.(float64)
ซึ่งใช้กับ interface เท่านั้น)
4. len("สวัสดี") คืนค่าอะไร?
len() ของ string นับ bytes เสมอ —
ตัวอักษรไทยใน UTF-8 ใช้ 3 bytes ต่อ rune และ "สวัสดี" มี 6 rune
(ส · ว · ◌ั · ส · ด · ◌ี — สระนับแยกด้วย) → 6 × 3 = 18
ตัวเลือกอื่นผิดเพราะ: 6 คือจำนวน rune ไม่ใช่สิ่งที่ len คืนให้ ·
3 ไม่ใช่ผลของอะไรเลย Go ไม่มีแนวคิดเรื่องพยางค์ ·
0 ก็ไม่ใช่ เพราะ Go เก็บ string เป็น UTF-8 อยู่แล้ว รองรับไทยเต็มที่
อยากได้ 6 ต้องเขียน len([]rune("สวัสดี"))
หรือ utf8.RuneCountInString(s)
7 · ลงมือทำ
ภารกิจ: ทำให้ compiler ด่าแล้วซ่อมให้ได้
- ใน Playground ประกาศตัวแปรทั้ง 3 แบบ
อย่างละ 1 ตัว แล้วพิมพ์ทั้งค่าและ type ด้วย
fmt.Printf("%v %T\n", x, x) - ประกาศ
var i int = 42และvar f float64 = 1.5แล้วลองi + f— อ่าน error ให้ครบทั้งบรรทัด แล้วซ่อม - เก็บใส่ตัวแปรก่อน แล้วค่อยแปลง:
f := 3.9; fmt.Println(int(f))และbig := 300; fmt.Println(uint8(big))— ทำนายผลก่อนรัน แล้วดูว่าตรงไหม - ทีนี้ลองแปลง ค่าคงที่ตรง ๆ:
int(3.9)และuint8(300)— คนละเรื่องกับข้อ 3 นะ อ่าน error แล้วอธิบายให้ได้ว่าทำไม Go ถึงยอมให้ทำข้อ 3 แต่ไม่ยอมข้อนี้ - ประกาศตัวแปร 1 ตัวแล้วไม่ใช้เลย — จำ error
declared and not usedไว้ให้ขึ้นใจ - พิมพ์
len("สวัสดี")เทียบกับlen([]rune("สวัสดี")) - ท้าทาย: เขียนโปรแกรมที่รับ
completedTopics,totalTopicsเป็นintแล้วพิมพ์เปอร์เซ็นต์ทศนิยม 2 ตำแหน่ง — คำใบ้:int / intได้int(5/2 = 2 ไม่ใช่ 2.5) ต้องแปลงก่อนหาร
เจอ error mismatched types หรือ
cannot use x (type A) as type B คุณจะไม่งงอีก —
รู้เลยว่าต้องหาจุดที่ต้องเขียน T(v) ครอบ
อ่านต่อจากต้นทาง
แหล่งหลักที่แนะนำ: A Tour of Go — Basic types (หน้า 8–14) กดรันแก้โค้ดได้ในหน้าเว็บเลย ทำให้ครบทั้ง 7 หน้า ใช้เวลาไม่เกิน 15 นาที และครอบคลุมทุกอย่างในบทนี้
💬 ติดตรงไหนถามได้เลย — ข้อ 7 ของภารกิจ (หาร int แล้วได้ int) เป็นบั๊กที่เจอในงานจริงบ่อยมาก ถ้าทำแล้วผลออกมาเป็น 0 หรือ 100 เป๊ะ ๆ แปลว่าเจอกับดักแล้ว ถามมาได้
อ้างอิง
- A Tour of Go — Basic types, Zero values, Type conversions, Type inference
- Go spec — Conversions — กฎการแปลง
T(v) - Go spec — The zero value
- Strings, bytes, runes and characters in Go — ทำไม
lenของภาษาไทยไม่ใช่จำนวนตัวอักษร - pkg.go.dev/fmt — รายการ format verb ทั้งหมด