How to Understand and Use nil in Golang Correctly?

  sonic0002        2024-01-05 05:19:40       2,371        0          English  简体中文  繁体中文  ภาษาไทย  Tiếng Việt 

ใน Golang, nil คือตัวระบุที่กำหนดไว้ล่วงหน้าซึ่งมีความหมายแตกต่างกันในบริบทต่างๆ แต่โดยทั่วไปแล้วจะแทน "ไม่มี", "ว่างเปล่า" หรือ "ค่าศูนย์" สามารถกำหนดให้กับตัวแปรประเภทตัวชี้, slice, map, channel, function และ interface การทำความเข้าใจความสำคัญของ nil นั้นมีความสำคัญอย่างยิ่งต่อการเขียนโปรแกรม Go ที่แข็งแกร่ง เนื่องจากการจัดการ nil ที่ไม่ถูกต้องอาจนำไปสู่ปัญหาที่ไม่คาดคิด

nil ในตัวชี้

ใน Go ตัวชี้เป็นชนิดข้อมูลพื้นฐานที่เก็บที่อยู่หน่วยความจำของตัวแปร เมื่อประกาศตัวชี้แต่ไม่ได้เริ่มต้นค่า ค่าของมันจะเป็น nil ตัวอย่างโค้ดต่อไปนี้แสดงให้เห็น

package main

import "fmt"

func main() {
	var ptr *int
	fmt.Println(ptr == nil) // true
}

ถ้าคุณอ้างอิงตัวชี้ nil มันจะส่งผลให้เกิด panic ดังนั้นจึงมีความสำคัญอย่างยิ่งที่จะต้องตรวจสอบว่าตัวชี้เป็น nil หรือไม่ก่อนที่จะดำเนินการใดๆ กับตัวชี้

nil ใน Slices

Slice คืออาร์เรย์แบบไดนามิกประกอบด้วยอาร์เรย์พื้นฐานและชุดข้อมูลที่อธิบายคุณสมบัติของ slice เมื่อประกาศ slice แต่ไม่ได้เริ่มต้นค่า ค่าของมันจะเป็น nil ตัวอย่างโค้ดต่อไปนี้แสดงให้เห็น

package main

import "fmt"

func main() {
	var s []int  
	fmt.Println(s == nil) // true
}

Slice nil ไม่ชี้ไปยังอาร์เรย์พื้นฐานที่ถูกต้อง และทั้งความยาว (len) และความจุ (cap) เป็น 0 อย่างไรก็ตาม slice nil และ slice ว่าง (สร้างด้วย make([]int, 0) หรือ []int{}) นั้นแตกต่างกัน Slice nil ไม่ใช้หน่วยความจำจนกว่าจะมีการจัดสรรพื้นที่ให้ ในขณะที่ slice ว่าง แม้ว่าจะมีความยาวเป็น 0 แต่ก็มีตัวชี้ชี้ไปยังอาร์เรย์พื้นฐานที่มีความยาว 0 อยู่แล้ว

nil ใน Maps

Map ใช้เพื่อเก็บคอลเลกชันของคู่คีย์-ค่า โดยที่คีย์นั้นไม่ซ้ำกัน เมื่อประกาศ map แต่ไม่ได้เริ่มต้นค่า ค่าของมันจะเป็น nil ซึ่งหมายความว่ายังไม่มีการจัดสรรพื้นที่หน่วยความจำ และไม่สามารถใช้งานได้โดยตรง ตัวอย่างโค้ดต่อไปนี้แสดงให้เห็น

package main

import "fmt"

func main() {
	var myMap map[string]int
	fmt.Println(myMap == nil)
}

การเขียนข้อมูลลงใน map nil จะส่งผลให้เกิด panic เนื่องจาก map nil ไม่มีโครงสร้างข้อมูลพื้นฐานในการเก็บข้อมูล อย่างไรก็ตาม การอ่านข้อมูลจาก map nil จะไม่ทำให้เกิดข้อผิดพลาด มันจะส่งคืนค่าศูนย์สำหรับชนิดข้อมูลที่เกี่ยวข้องเท่านั้น

Map nil และ map ที่ไม่มีคู่คีย์-ค่า (map ว่าง) นั้นแตกต่างกัน Map nil ไม่สามารถใช้เพื่อเก็บคู่คีย์-ค่าได้ ในขณะที่ map ว่างได้รับการเริ่มต้นแล้วแต่ไม่มีองค์ประกอบ ตัวอย่างเช่น:

// nil map
var nilMap map[string]int

// e,pty map
emptyMap := make(map[string]int)

คุณสามารถจัดการ map ว่าง เช่น การเพิ่มหรือลบคู่คีย์-ค่าได้ อย่างไรก็ตาม การดำเนินการเหล่านี้กับ map nil จะส่งผลให้เกิด panic

nil ใน Channels

Channels เป็น primitive สำหรับการซิงโครไนซ์ใน Go ใช้สำหรับส่งข้อความระหว่าง Go routines (goroutines) เมื่อประกาศ channel แต่ไม่ได้เริ่มต้นค่า ค่าของมันจะเป็น nil ตัวอย่างโค้ดต่อไปนี้แสดงให้เห็น

package main

import "fmt"

func main() {
	var ch chan int        
	fmt.Println(ch == nil) // true
}

การพยายามส่งหรือรับข้อมูลบน channel nil จะบล็อกอย่างไม่มีกำหนด เนื่องจาก channel nil ไม่ได้ถูกปิดและไม่มี goroutine อื่นที่จะดำเนินการส่งหรือรับ อย่างไรก็ตาม channel nil มีวัตถุประสงค์พิเศษในคำสั่ง select และสามารถใช้เพื่อปิดใช้งานสาขาเฉพาะในคำสั่ง select ได้

nil ใน Functions

ใน Go ฟังก์ชันก็เป็นชนิดข้อมูลเช่นกัน และคุณสามารถใช้ nil เพื่อแทนฟังก์ชันที่ไม่ได้เริ่มต้นค่า ตัวอย่างโค้ดต่อไปนี้แสดงให้เห็น

package main

import "fmt"

func main() {
	var fn func(int) int   
	fmt.Println(fn == nil) // true
}

การเรียกใช้ฟังก์ชัน nil จะส่งผลให้เกิด panic

nil ใน Interfaces

Interface เป็นคุณสมบัติที่สำคัญใน Go แทนชนิดข้อมูลนามธรรม เมื่อประกาศตัวแปร interface ใหม่โดยไม่ให้การใช้งานที่เป็นรูปธรรม ค่าของมันจะเป็น nil ตัวอย่างเช่น

package main

import "fmt"

func main() {
	var i interface{}
	fmt.Println(i == nil) // true
}

ภายใน Go ตัวแปรชนิด interface{} ประกอบด้วยสองส่วน: ชนิด (Type) และค่า (Value) ตัวแปร interface{} จะถือว่า nil เฉพาะเมื่อไม่มีทั้งชนิดและค่า พิจารณาตัวอย่างต่อไปนี้:

package main

import "fmt"

type MyInterface interface {
	Method()
}

type MyType struct{}

func (mt *MyType) Method() {}

func main() {
	var mt *MyType = nil
	var i MyInterface = mt
	fmt.Println(i == nil)
}

แม้ว่า mt จะเป็นตัวชี้ nil แต่เมื่อกำหนดให้กับชนิด interface i แล้ว i ยังคงเก็บข้อมูลชนิดของ MyType ไว้ ดังนั้น i จึงไม่ใช่ nil

แนวทางปฏิบัติที่ดีที่สุดเพื่อหลีกเลี่ยงปัญหาที่เกี่ยวข้องกับ nil

  1. ก่อนที่จะใช้ตัวแปรประเภทตัวชี้, slice, map, channel และฟังก์ชัน ให้ตรวจสอบว่าเป็น nil หรือไม่
  2. ทำความเข้าใจความแตกต่างระหว่างค่าศูนย์และ nil สำหรับชนิดข้อมูลบางชนิด เช่น slice, map, channel และ interface, nil แทนค่าศูนย์ของพวกมัน อย่างไรก็ตาม ค่าศูนย์สำหรับชนิดข้อมูลไม่จำเป็นต้องเป็น nil (เช่น ชนิดข้อมูลตัวเลขและ struct)
  3. เมื่อฟังก์ชันส่งคืนชนิด interface ให้หลีกเลี่ยงการส่งคืนตัวชี้ nil ของชนิดข้อมูลที่เป็นรูปธรรม เนื่องจากอาจทำให้เกิดความสับสนเมื่อค่า interface ไม่ใช่ nil
  4. เมื่อฟังก์ชันส่งคืนข้อผิดพลาด ให้ส่งคืน nil แทนที่จะเป็น instance nil ของชนิดข้อผิดพลาดหากไม่มีข้อผิดพลาดเกิดขึ้น
  5. ก่อนที่จะปิดทรัพยากร เช่น ไฟล์และการเชื่อมต่อฐานข้อมูล ให้ตรวจสอบว่าเป็น nil หรือไม่เพื่อหลีกเลี่ยงการอ้างอิงตัวชี้ nil

สรุป

nil เป็นแนวคิดที่สำคัญใน Golang และการทำความเข้าใจอย่างลึกซึ้งเกี่ยวกับการประยุกต์ใช้ในโปรแกรม Go นั้นมีความสำคัญอย่างยิ่งต่อการเขียนโค้ด Go คุณภาพสูง บทความนี้มีจุดมุ่งหมายเพื่อช่วยให้คุณเข้าใจความรู้เกี่ยวกับ nil ได้ดียิ่งขึ้น

FUNCTION  MAP  GOLANG  SLICE  NIL  CHANNEL 

       

  RELATED


  0 COMMENT


No comment for this article.



  RANDOM FUN

Release day