0Pricing
Go Academy · บทเรียน

พอยน์เตอร์และฟังก์ชัน

การส่งผ่านค่าเปรียบเทียบกับการส่งผ่านพอยน์เตอร์

พอยน์เตอร์และฟังก์ชัน เป็นบทเรียน Go Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Go Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Go Academy มีบทเรียนทั้งหมด 4 บทเรียน

การส่งผ่านด้วยค่า

Go ส่งอาร์กิวเมนต์ของฟังก์ชันทั้งหมดด้วยค่า ซึ่งหมายความว่าจะมีการสร้างสำเนา การเปลี่ยนแปลงภายในฟังก์ชันจะไม่ส่งผลต่อต้นฉบับ:

package main
import "fmt"

func increment(n int) { n++ }

func main() {
    x := 5
    increment(x)
    fmt.Println(x) // 5 — unchanged
}

ส่งผ่านด้วยพอยน์เตอร์

ส่งพอยน์เตอร์เพื่อให้ฟังก์ชันแก้ไขค่าต้นฉบับได้:

package main
import "fmt"

func increment(n *int) { *n++ }

func main() {
    x := 5
    increment(&x)
    fmt.Println(x) // 6
}

การคืนค่าพอยน์เตอร์

ฟังก์ชันสามารถคืนค่าพอยน์เตอร์ไปยังค่าที่จัดสรรบนฮีปได้ การวิเคราะห์การหลุดรอดของ Go จะช่วยรับประกันความปลอดภัย:

package main
import "fmt"

func newInt(v int) *int { return &v }

func main() {
    p := newInt(42)
    fmt.Println(*p) // 42
}

ประสิทธิภาพของโครงสร้างขนาดใหญ่

การส่งโครงสร้างขนาดใหญ่ด้วยพอยน์เตอร์ช่วยหลีกเลี่ยงการคัดลอกที่ใช้ทรัพยากรมาก:

package main
import "fmt"

type BigData struct{ Data [1024]int }

func process(d *BigData) { d.Data[0] = 99 }

func main() {
    bd := BigData{}
    process(&bd)
    fmt.Println(bd.Data[0]) // 99
}

พอยน์เตอร์ไปยังอินเทอร์เฟซ

แทบไม่จำเป็นต้องใช้ — อินเทอร์เฟซมีพอยน์เตอร์อยู่ภายในแล้ว การส่ง *interface{} มักเป็นสิ่งที่ผิดเกือบทุกครั้ง:

package main
import "fmt"

type Stringer interface{ String() string }

func print(s Stringer) { fmt.Println(s.String()) }

// Pass interface directly, NOT *Stringer
type Name string
func (n Name) String() string { return string(n) }

func main() {
    print(Name("Alice"))
}

พารามิเตอร์ที่ไม่บังคับด้วยพอยน์เตอร์

ใช้พารามิเตอร์แบบพอยน์เตอร์เพื่อแยกความแตกต่างระหว่าง "ไม่ได้ระบุ" กับค่าศูนย์:

package main
import "fmt"

func greet(name *string) {
    if name == nil {
        fmt.Println("Hello, stranger")
        return
    }
    fmt.Println("Hello,", *name)
}

func main() {
    s := "Alice"
    greet(&s)
    greet(nil)
}

การแก้ไขค่าผ่านสไลซ์

สไลซ์มีพอยน์เตอร์อยู่ภายในแล้ว ดังนั้นโดยมากจึงไม่จำเป็นต้องใช้ *[]T อย่างไรก็ตาม เมื่อ append จัดสรรหน่วยความจำใหม่ คุณจำเป็นต้องใช้พอยน์เตอร์ไปยังสไลซ์นั้นเอง:

package main
import "fmt"

func addItem(s *[]int, v int) { *s = append(*s, v) }

func main() {
    nums := []int{1, 2, 3}
    addItem(&nums, 4)
    fmt.Println(nums) // [1 2 3 4]
}

การใช้นามแฝงของพอยน์เตอร์

พอยน์เตอร์หลายตัวที่ชี้ไปยังตัวแปรเดียวกันจะทำให้เกิดการใช้นามแฝง — การเปลี่ยนแปลงผ่านพอยน์เตอร์ตัวหนึ่งจะมองเห็นได้ผ่านพอยน์เตอร์ตัวอื่นทั้งหมด:

package main
import "fmt"

func main() {
    x := 10
    a, b := &x, &x
    *a = 99
    fmt.Println(*b) // 99 — same memory
}

การหลีกเลี่ยงการใช้พอยน์เตอร์มากเกินไป

ใช้พอยน์เตอร์เมื่อจำเป็นเท่านั้น:

  • การแก้ไขค่าภายในฟังก์ชัน
  • โครงสร้างขนาดใหญ่ (ตั้งแต่ประมาณ 64 ไบต์ขึ้นไป)
  • ใช้ nil เพื่อหมายถึง "ไม่มีค่า"

การใช้พอยน์เตอร์มากเกินไปเพิ่มภาระให้ GC และทำให้โค้ดอ่านเข้าใจได้ยากขึ้น

รูปแบบพอยน์เตอร์ฟังก์ชัน

เก็บพอยน์เตอร์ฟังก์ชันไว้ในแมปสำหรับตารางกระจายงาน:

package main
import "fmt"

func add(a, b int) int { return a + b }
func sub(a, b int) int { return a - b }

func main() {
    ops := map[string]func(int,int)int{
        "+": add, "-": sub,
    }
    fmt.Println(ops["+"](10, 3)) // 13
    fmt.Println(ops["-"](10, 3)) // 7
}

ตรวจสอบอย่างรวดเร็ว

คุณจะทำให้ฟังก์ชันแก้ไขตัวแปรจำนวนเต็มที่กำหนดไว้ในฟังก์ชันผู้เรียกได้อย่างไร

สรุปทบทวน

ประเด็นสำคัญ:

  • Go ส่งผ่านค่าด้วยการคัดลอก — ใช้พอยน์เตอร์เมื่อต้องการแก้ไขค่า
  • คืนค่าพอยน์เตอร์จากฟังก์ชันสร้างเพื่อจัดสรรบนฮีป
  • สไลซ์มีพอยน์เตอร์ภายใน แต่ append อาจจำเป็นต้องใช้ *[]T
  • หลีกเลี่ยงการใช้พอยน์เตอร์มากเกินไป — เลือกใช้ค่าแทนสำหรับชนิดข้อมูลขนาดเล็ก

โจทย์ฝึกปฏิบัติ

เขียนฟังก์ชัน normalize ที่รับ *[]string และแปลงสตริงทั้งหมดเป็นตัวพิมพ์เล็กภายในสไลซ์เดิม โดยใช้ strings.ToLower

คำถามที่พบบ่อย

บทเรียน “พอยน์เตอร์และฟังก์ชัน” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “พอยน์เตอร์และฟังก์ชัน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Go Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Go Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “พอยน์เตอร์และฟังก์ชัน”

การส่งผ่านค่าเปรียบเทียบกับการส่งผ่านพอยน์เตอร์ คุณปฏิบัติ Go Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Go Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Go Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “พอยน์เตอร์และฟังก์ชัน” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Go Academy นี้ได้ไหม

ได้ บทเรียน Go Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. พอยน์เตอร์คืออะไร
  2. พอยน์เตอร์และฟังก์ชัน
  3. ตัวรับพอยน์เตอร์ในเมธอด
  4. new() และกรณีที่ควรใช้พอยน์เตอร์
← กลับไปที่ Go Academy