ข้ามไปยังเนื้อหา

Pointers (ตัวชี้)

ใน TypeScript (และ JavaScript) object ถูกส่งต่อเป็น reference โดยอัตโนมัติ คุณไม่เคยต้องเขียนว่า “ขอ address ของตัวแปรนี้” เพราะ runtime จัดการ memory ให้เบื้องหลังโดยที่คุณมองไม่เห็น

Go เปิดเผย memory address อย่างชัดเจน คุณเลือกเองว่า function จะรับ copy ของค่าหรือ pointer ไปยังต้นฉบับ การเลือกนั้นมีผลจริงต่อความถูกต้องและประสิทธิภาพ

&x ให้ pointer ไปยัง x — address ใน memory ที่ x อาศัยอยู่ *p dereference pointer p — อ่านหรือเขียนค่าที่ address นั้น

TypeScript
// TypeScript — objects are implicitly shared
function increment(obj: { count: number }) {
obj.count++; // mutates the original (reference)
}
const counter = { count: 0 };
increment(counter);
console.log(counter.count); // 1
// BUT primitives are always copied:
function addOne(n: number): number {
return n + 1; // n is a copy — caller unchanged
}
let x = 5;
addOne(x);
console.log(x); // still 5
Go
// Go — primitives copied by default; use * to opt in to mutation
func increment(n *int) {
*n++ // dereference and mutate
}
func main() {
x := 42
increment(&x) // pass address of x
fmt.Println(x) // 43 — x was mutated
// Without pointer — value is copied, caller unchanged
// increment(x) would be a compile error (type mismatch)
}

ทุก type T มี pointer type *T ที่สอดคล้องกัน ตัวแปร pointer เก็บ address ไม่ใช่ค่า

TypeScript
// TypeScript has no pointer types
// The closest is a wrapper object or ref pattern:
const ref = { current: 0 }; // manual "pointer" idiom
Go
var p *int // p is a pointer to int, value is nil
x := 10
p = &x // p now holds the address of x
fmt.Println(*p) // 10 — dereference to read
*p = 20 // write through pointer
fmt.Println(x) // 20

มีสองเหตุผลหลักในการใช้ pointer:

  1. Mutation — คุณต้องการให้ function แก้ไขตัวแปรของ caller (ไม่ใช่ทำงานกับ copy)
  2. Efficiency — struct มีขนาดใหญ่และการ copy ทุกครั้งที่เรียกจะสิ้นเปลือง

สำหรับ struct ขนาดเล็ก (2–3 field) ที่อ่านอย่างเดียว มักใช้ value semantics ได้ สำหรับ struct ขนาดใหญ่หรือจุดที่ต้องการ mutation ให้ใช้ pointer

TypeScript
// TypeScript — structs/objects always pass by reference
// You have no choice; the runtime decides
interface Config { host: string; port: number; }
function connect(cfg: Config) { /* cfg is a reference */ }
Go
type Config struct {
Host string
Port int
}
// Value receiver — method gets a copy; cannot modify original
func (c Config) String() string {
return fmt.Sprintf("%s:%d", c.Host, c.Port)
}
// Pointer receiver — method can modify the original
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 to struct
type Point struct{ X, Y int }
p := &Point{X: 1, Y: 2}
p.X = 99 // Go auto-dereferences: (*p).X = 99
fmt.Println("point:", *p)
}
&x ใน Go หมายความว่าอะไร?
*p หมายความว่าอะไรเมื่อ p เป็น pointer?
Zero value ของตัวแปร pointer ใน Go คืออะไร?
คุณมี func double(n int) จะทำอย่างไรให้ double สามารถแก้ไขตัวแปรของ caller ได้?