Implement struct no copy in GoLang

English 简体中文 繁体中文 ภาษาไทย Tiếng Việt
Summary

GoLang lacks an intuitive mechanism to prevent struct copying, which can be problematic for types like global configurations that should maintain a single instance. A common pattern to address this involves embedding a special noCopy struct within any type not intended for copying. This noCopy struct, which implements the sync.Locker interface with no-op Lock() and Unlock() methods, enables the go vet tool to identify instances where the containing struct is copied by value. While go vet will report warnings for such copies, the code will still compile and run successfully, making this approach a valuable development-time check rather than a compile-time enforcement.

มีบางกรณีที่โครงสร้างบางตัวใน GoLang ไม่ได้ถูกสร้างมาเพื่อการคัดลอก ตัวอย่างเช่น บางครั้งการกำหนดค่าทั่วโลกซึ่งควรมีเพียงเวอร์ชันเดียวที่ส่งผ่านไปทั่วทั้งแอปพลิเคชันและไม่ควรคัดลอกและแก้ไข

ใน GoLang ไม่มีวิธีแก้ปัญหาที่เข้าใจง่ายในการป้องกันการคัดลอกโครงสร้าง แต่ก็ยังมีวิธีการบางอย่างที่สามารถใช้เพื่อช่วยป้องกันสิ่งนี้ในขณะที่พัฒนาโค้ด กลอุบายคือการกำหนดโครงสร้างบางอย่างที่ใช้ interface sync.Locker และมีโครงสร้างนี้ฝังอยู่ในโครงสร้างใดๆ ที่ไม่ต้องการให้คัดลอก

// noCopy อาจถูกฝังอยู่ในโครงสร้างที่ไม่ควรคัดลอก
// หลังจากการใช้งานครั้งแรก
//
// ดู https://golang.org/issues/8005#issuecomment-190753527
// สำหรับรายละเอียด
type noCopy struct{}

// Lock เป็น no-op ที่ใช้โดยตัวตรวจสอบ -copylocks จาก `go vet`
func (*noCopy) Lock() {}
func (*noCopy) UnLock() {}

ด้านล่างนี้เป็นตัวอย่างสั้นๆ ที่อธิบายข้างต้น

package main

import (
	"fmt"
)

type noCopy struct{}

func (*noCopy) Lock()   {}
func (*noCopy) Unlock() {}

type Demo struct {
	noCopy noCopy
}

func Copy(d Demo) {
}

func main() {
	d := Demo{}
	fmt.Printf("%+v", d)

	Copy(d)

	fmt.Printf("%+v", d)
}

ตอนนี้ถ้าคุณรัน go vet บนไฟล์ main.go คุณจะเห็นข้อผิดพลาดบางอย่างบอกคุณว่าคุณมีการคัดลอกโครงสร้างบางแห่ง (Copy())

> go vet main.go
# command-line-arguments
.\main.go:16: Copy ส่งผ่าน lock โดยค่า: main.Demo ประกอบด้วย main.noCopy
.\main.go:21: การเรียกใช้ fmt.Printf คัดลอกค่า lock: main.Demo ประกอบด้วย main.noCopy
.\main.go:23: การเรียกใช้ Copy คัดลอกค่า lock: main.Demo ประกอบด้วย main.noCopy
.\main.go:25: การเรียกใช้ fmt.Printf คัดลอกค่า lock: main.Demo ประกอบด้วย main.noCopy

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

> go run main.go
{noCopy:{}}{noCopy:{}}

อ้างอิง:

GO VET NOCOPY NO COPY

  RELATED

  COMMENTS

0

No comment for this article.