Null, nil, None — คำว่า "ไม่มีค่า" ในแต่ละภาษา
เวลาเราเขียนโปรแกรม — วันนึงเราจะต้องเจอ "การไม่มีค่า"
บางภาษามันคือ null บางภาษามันคือ nil บางภาษามันคือ None — แต่มันคือสิ่งเดียวกันใช่ไหม?
ไม่ใช่ — และความต่างเล็ก ๆ นี่แหละที่ทำให้โปรแกรมพังได้
ภาพรวม — แต่ละภาษาเรียกชื่ออะไร
| ภาษา | ชื่อเรียก | ตัวอย่าง |
|---|---|---|
| Java | null |
String s = null; |
| JavaScript |
null + undefined
|
let x = null; let y; |
| Python | None |
x = None |
| Ruby | nil |
x = nil |
| C/C++ |
NULL / nullptr
|
int* p = NULL; |
| Go |
nil + zero values
|
var s *string = nil |
เห็นว่า Ruby กับ Go ใช้ nil เหมือนกัน — แต่เบื้องหลังต่างกันโดยสิ้นเชิง
Java — null คือตัวปัญหา
String name = null;
System.out.println(name.length()); // 💥 NullPointerException!
ใน Java — null คือ "การไม่มี object" — และทุกครั้งที่คุณเรียก method บน null — โปรแกรมพัง
Java แก้ด้วยการเช็ค if (x != null) ทุกที่ — หรือใช้ Optional (Java 8+) — แต่ null ก็ยังแฝงตัวอยู่ทุกมุม
// Java Optional — พยายามกำจัด null
Optional<String> name = Optional.ofNullable(getName());
name.ifPresent(System.out::println);
JavaScript — มีสองแบบ ซวยสองเท่า
let x = null; // "ฉันจงใจให้มันว่าง"
let y; // undefined — "ฉันลืมใส่ค่า"
console.log(x); // null
console.log(y); // undefined
console.log(typeof null); // "object" ← bug ในภาษา!
null == undefined; // true ← อ้าว?
null === undefined; // false ← อ้าววว?
JavaScript มีทั้ง null และ undefined — และการที่ typeof null === "object" เป็น bug ที่ฝังมาตั้งแต่ปี 1995 — แก้ไม่ได้แล้วเพราะคนใช้กันทั้งโลก
Python — None คือ singleton
x = None
y = None
print(x is y) # True — None มีตัวเดียวในจักรวาล
ใน Python — None เป็น singleton — มีแค่ instance เดียวในหน่วยความจำ — is ใช้เช็คได้
def get_user(id):
return None # "ไม่เจอ"
user = get_user(42)
if user is None:
print("ไม่พบผู้ใช้")
สะอาด ตรงไปตรงมา — ไม่มี NullPointerException — แต่ก็ไม่ได้ช่วยให้ปลอดภัยขึ้น — ถ้าลืมเช็ค None — โปรแกรมก็พังตอนใช้ user.name อยู่ดี
Go — nil คืออะไร? และทำไมมันถึงหลอกเรา
Go ใช้ nil — แต่ความหมายของมันเปลี่ยนไปตาม type
var p *int = nil // nil pointer
var s []int = nil // nil slice — แต่ใช้ append ได้!
var m map[string]int = nil // nil map — อ่านได้ แต่เขียนไม่ได้!
var ch chan int = nil // nil channel — block ตลอดกาล
var fn func() = nil // nil function — เรียกแล้ว panic
nil slice: ต่างจากภาษาอื่น — คุณใช้ append บน nil slice ได้!
var names []string // nil slice — len=0
names = append(names, "Alice") // ✅ ได้เลย! ไม่ต้อง make ก่อน
fmt.Println(names) // [Alice]
nil map: อ่านได้ แต่เขียนไม่ได้:
var m map[string]int // nil map
_ = m["key"] // ✅ ได้ 0 (zero value)
m["key"] = 1 // 💥 panic: assignment to entry in nil map
หลุมพรางใน Go — nil interface ≠ nil pointer
นี่คือ bug ที่คนเขียน Go เจอแล้วเจออีก:
func getUser() *User {
return nil // ไม่มี user
}
func getUserAsInterface() error {
return getUser() // return nil pointer
}
func main() {
err := getUserAsInterface()
if err != nil {
fmt.Println("มี error!") // ❌ มันเข้าเงื่อนไขนี้ทั้งที่ควรเป็น nil!
}
}
ทำไม? interface ใน Go ไม่ใช่แค่ "ค่า" — มันคือ (type, value) — tuple:
var p *User = nil
fmt.Println(p == nil) // true — pointer nil
var err error = p // เก็บ (*User, nil) — type ไม่ใช่ nil!
fmt.Println(err == nil) // false!?
interface err มี type = *User (ไม่ใช่ nil) — แต่ value = nil — interface โดยรวมจึง ไม่ใช่ nil
วิธีแก้: return nil แบบไม่มี type — ไม่ใช่แค่ pointer nil:
func getUserAsInterface() error {
u := getUser()
if u == nil {
return nil // ✅ nil แบบไม่มี type — interface nil จริง
}
return u
}
Zero Values — Go ไม่มี "ไม่มีค่า"
แนวคิดที่ต่างจากภาษาอื่นมาก: Go ไม่มี uninitialized variable
var i int // 0
var s string // "" (empty string — ไม่ใช่ nil!)
var b bool // false
var p *int // nil (แต่ type ชัดเจนว่าเป็น *int)
ใน Java/Python/JS — ตัวแปรที่ยังไม่ assign ค่าอาจเป็น null/None/undefined
ใน Go — ทุกอย่างมี zero value — ค่าเริ่มต้นของ type นั้น — คุณไม่ต้องกลัวว่าจะลืม initialize
type User struct {
Name string // "" (ไม่ใช่ nil)
Age int // 0
}
var u User
fmt.Println(u.Name) // "" — ไม่พัง!
เปรียบเทียบกับ Java:
class User {
String name; // null!
int age; // 0
}
User u = new User();
u.name.length(); // 💥 NullPointerException!
เทียบกัน — ภาษาไหนชนะ
| null error | zero value | nil slice ใช้ได้ | interface nil trap | |
|---|---|---|---|---|
| Go | ❌ (แต่มี interface trap) | ✅ | ✅ | ⚠️ หลุมพราง |
| Java | 💥 NullPointerException | ❌ (Object = null) | — | — |
| JavaScript | 💥 undefined + null | — | — | — |
| Python | 💥 AttributeError | ❌ | — | — |
| Ruby | 💥 NoMethodError | ❌ | — | — |
สรุป
| ภาษา | ชื่อ | จุดอ่อน |
|---|---|---|
| Java | null |
NullPointerException ทุกที่ — Optional ช่วยได้นิดหน่อย |
| JavaScript |
null, undefined
|
สองแบบ — typeof null === "object"
|
| Python | None |
สะอาดสุด — แต่ต้องเช็ค is None เอง |
| Go |
nil + zero values |
ปลอดภัยกว่า — แต่ interface nil trap หลอกได้ |
หัวใจของ Go: ตัวแปรทุกตัวมีค่าเสมอ — แม้จะเป็น "ค่าเริ่มต้น" — คุณจะไม่เจอ NullPointerException ใน Go — แต่คุณจะเจอ "interface nil trap" แทน
และนั่นคือบทเรียนที่คนเขียน Go ทุกคนต้องผ่าน — nil กับ nil มันไม่เหมือนกัน
📚 อ่านต่อ:
Top comments (0)