Pointers (ตัวชี้)
TypeScript ไม่มี pointer แบบ explicit
หัวข้อที่มีชื่อว่า “TypeScript ไม่มี pointer แบบ explicit”ใน TypeScript (และ JavaScript) object ถูกส่งต่อเป็น reference โดยอัตโนมัติ คุณไม่เคยต้องเขียนว่า “ขอ address ของตัวแปรนี้” เพราะ runtime จัดการ memory ให้เบื้องหลังโดยที่คุณมองไม่เห็น
Go เปิดเผย memory address อย่างชัดเจน คุณเลือกเองว่า function จะรับ copy ของค่าหรือ pointer ไปยังต้นฉบับ การเลือกนั้นมีผลจริงต่อความถูกต้องและประสิทธิภาพ
Operator & และ *
หัวข้อที่มีชื่อว่า “Operator & และ *”&x ให้ pointer ไปยัง x — address ใน memory ที่ x อาศัยอยู่
*p dereference pointer p — อ่านหรือเขียนค่าที่ address นั้น
// TypeScript — object ถูกแชร์แบบ implicitfunction increment(obj: { count: number }) { obj.count++; // mutate ต้นฉบับ (reference)}
const counter = { count: 0 };increment(counter);console.log(counter.count); // 1
// แต่ primitive ถูก copy เสมอ:function addOne(n: number): number { return n + 1; // n คือ copy — caller ไม่เปลี่ยน}let x = 5;addOne(x);console.log(x); // ยังเป็น 5// Go — primitive ถูก copy โดยค่าเริ่มต้น; ใช้ * เพื่อ opt in การ mutatefunc increment(n *int) { *n++ // dereference แล้ว mutate}
func main() { x := 42 increment(&x) // ส่ง address ของ x fmt.Println(x) // 43 — x ถูก mutate
// ถ้าไม่ใช้ pointer — value จะถูก copy, caller ไม่เปลี่ยน // increment(x) จะเป็น compile error (type ไม่ตรง)}Pointer types
หัวข้อที่มีชื่อว่า “Pointer types”ทุก type T มี pointer type *T ที่สอดคล้องกัน ตัวแปร pointer เก็บ address ไม่ใช่ค่า
// TypeScript ไม่มี pointer type// ที่ใกล้ที่สุดคือ wrapper object หรือ ref pattern:const ref = { current: 0 }; // "pointer" แบบ manualvar p *int // p คือ pointer ไปยัง int, ค่าคือ nilx := 10p = &x // p เก็บ address ของ xfmt.Println(*p) // 10 — dereference เพื่ออ่าน*p = 20 // เขียนผ่าน pointerfmt.Println(x) // 20เมื่อไหร่ควรใช้ pointer ใน Go
หัวข้อที่มีชื่อว่า “เมื่อไหร่ควรใช้ pointer ใน Go”มีสองเหตุผลหลักในการใช้ pointer:
- Mutation — คุณต้องการให้ function แก้ไขตัวแปรของ caller (ไม่ใช่ทำงานกับ copy)
- Efficiency — struct มีขนาดใหญ่และการ copy ทุกครั้งที่เรียกจะสิ้นเปลือง
สำหรับ struct ขนาดเล็ก (2–3 field) ที่อ่านอย่างเดียว มักใช้ value semantics ได้ สำหรับ struct ขนาดใหญ่หรือจุดที่ต้องการ mutation ให้ใช้ pointer
// TypeScript — struct/object ส่งเป็น reference เสมอ// คุณไม่มีทางเลือก; runtime ตัดสินใจinterface Config { host: string; port: number; }function connect(cfg: Config) { /* cfg คือ reference */ }type Config struct { Host string Port int}
// Value receiver — method รับ copy; ไม่สามารถแก้ไขต้นฉบับfunc (c Config) String() string { return fmt.Sprintf("%s:%d", c.Host, c.Port)}
// Pointer receiver — method สามารถแก้ไขต้นฉบับfunc (c *Config) SetPort(p int) { c.Port = p}
func main() { cfg := Config{Host: "localhost", Port: 8080} cfg.SetPort(9090) fmt.Println(cfg.String()) // localhost:9090}package main
import "fmt"
func increment(n *int) { *n++}
func swap(a, b *int) { *a, *b = *b, *a}
func main() { x := 42 fmt.Println("before:", x) increment(&x) fmt.Println("after increment:", x)
a, b := 10, 20 fmt.Printf("before swap: a=%d b=%d\n", a, b) swap(&a, &b) fmt.Printf("after swap: a=%d b=%d\n", a, b)
// Pointer ไปยัง struct type Point struct{ X, Y int } p := &Point{X: 1, Y: 2} p.X = 99 // Go auto-dereference: (*p).X = 99 fmt.Println("point:", *p)}Loading Go runtime (first run only, ~8 MB)…