
ด้วยการเปิดตัว Go 1.22 ทีม Go ได้แก้ไขปัญหาที่ยืนยงมาอย่างยาวนาน เกี่ยวกับขอบเขตตัวแปรวนซ้ำ for-range ซึ่งเป็นกับดักทั่วไปสำหรับนักพัฒนาที่เขียนโค้ดแบบขนาน โดยเฉพาะอย่างยิ่ง ปัญหาคือตัวแปรวนซ้ำในลูป for-range นั้นถูกนำกลับมาใช้ใหม่ในแต่ละรอบ ทำให้เกิดพฤติกรรมที่ไม่คาดคิดเมื่อมีการใช้ closures
ปัญหา ก่อน Go 1.22
ลองพิจารณาตัวอย่างต่อไปนี้:
package forange
import "fmt"
func Do() {
done := make(chan bool)
values := []string{"a", "b", "c"}
for _, v := range values {
go func() {
fmt.Println(v) // พิมพ์ค่าที่ไม่คาดคิด
done <- true
}()
}
for _ = range values {
<-done
}
}
และมีไฟล์ go.mod ดังต่อไปนี้
module playground
go 1.16
require github.com/ozgio/strutil v0.4.0
ในเวอร์ชันของ Go ก่อน 1.22 การรันโค้ดนี้มักส่งผลให้พิมพ์ค่าเดียวกัน (เช่น c) หลายครั้ง แทนที่จะพิมพ์แต่ละค่าใน values (a, b, c) ตามที่คาดไว้ นี่เป็นเพราะตัวแปรวนซ้ำ v ถูกนำกลับมาใช้ใหม่ในแต่ละรอบ และ goroutines ได้จับที่อยู่หน่วยความจำเดียวกัน
การแก้ไข Go 1.22
Go 1.22 ได้แนะนำการแก้ไขพฤติกรรมนี้โดยทำให้ตัวแปรวนซ้ำทำงานราวกับว่ามันถูกประกาศใหม่ในแต่ละรอบ ซึ่งหมายความว่าแต่ละ closure ควรจับค่าของ v สำหรับการวนซ้ำที่ตรงกันได้อย่างถูกต้อง
อย่างไรก็ตาม หากคุณอัปเกรดเป็น Go 1.22 แล้วและยังคงเห็นพฤติกรรมเก่าที่เป็นปัญหาอยู่ ผู้กระทำผิดอาจเป็นไฟล์ go.mod ของคุณ การแก้ไขจะมีผลก็ต่อเมื่อไฟล์ go.mod ระบุเวอร์ชัน Go เป็น 1.22 หรือสูงกว่า การพึ่งพานี้เป็นเจตนาและอนุญาตให้นักพัฒนาคงความเข้ากันได้แบบย้อนหลังกับพฤติกรรมเก่าได้หากจำเป็น
เมื่อระบุ go 1.22 ใน go.mod ของคุณและมีการใช้การแก้ไข การรันโปรแกรมข้างต้นควรพิมพ์ a, b, c ได้อย่างถูกต้อง แต่ละ goroutine ตอนนี้จับค่าที่เหมาะสมของ v สำหรับการวนซ้ำของมัน
บทเรียนที่ได้รับ
- อัปเดตอยู่เสมอ: อ่านบันทึกย่อประจำการเผยแพร่สำหรับเวอร์ชัน Go ใหม่เสมอ บันทึกย่อประจำการเผยแพร่ Go 1.22 กล่าวถึงโดยเฉพาะ การเปลี่ยนแปลงนี้และการพึ่งพา
go.mod - ใช้เวอร์ชัน
go.modที่ถูกต้อง: คุณลักษณะภาษา Go หลายอย่างถูกผูกไว้กับเวอร์ชันgoในgo.modหากคุณกำลังพึ่งพาคุณลักษณะหรือการแก้ไขใหม่ โปรดตรวจสอบให้แน่ใจว่าได้ระบุเวอร์ชันที่ถูกต้อง - ทดสอบอย่างละเอียด: แม้หลังจากอัปเกรด Go แล้ว โปรดตรวจสอบให้แน่ใจว่าโปรแกรมของคุณทำงานได้ตามที่คาดไว้โดยการรันการทดสอบที่ครอบคลุม
เหตุใดการพึ่งพานี้จึงจำเป็น
วิธีการเวอร์ชัน go.mod ช่วยให้ทีมต่างๆ สามารถนำการแก้ไขมาใช้ได้ทีละน้อยโดยไม่ทำลายการสร้างที่มีอยู่ โดยการเชื่อมโยงพฤติกรรมภาษาใหม่กับเวอร์ชัน go ใน go.mod ทีม Go จึงมั่นใจได้ถึงความเข้ากันได้แบบย้อนหลังในขณะที่ช่วยให้การโยกย้ายสำหรับนักพัฒนาเป็นไปอย่างราบรื่นยิ่งขึ้น
หากคุณเคยประสบกับความท้าทายที่คล้ายคลึงกันหรือมีข้อมูลเชิงลึกเกี่ยวกับวิธีการที่ส่งผลกระทบต่อเวิร์กโฟลว์ของคุณ โปรดแบ่งปันในความคิดเห็น!
Nice article?