ข้อผิดพลาดที่อาจเกิดขึ้นจากการเปิดใช้งานการเชื่อมคำศัพท์สำหรับบัฟเฟอร์คืออะไร?


12

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

การใช้ความเข้ากันได้แบบย้อนหลังกับ Emacsen รุ่นเก่านั้นไม่ได้เป็นปัญหาที่คุณควรมองหาหากเปิดใช้งานในบัฟเฟอร์รหัสดั้งเดิม

คำตอบ:


13

อันตรายที่สำคัญคือความหมายผูกพันที่ไม่ได้กำหนดตัวแปรตัวแปรคือไม่กำหนดด้วยdefvarและเพื่อน ๆ เปลี่ยนกับlexical-binding: โดยไม่ได้letผูกทุกอย่างแบบไดนามิก แต่มีlexical-bindingตัวแปรที่ไม่ได้กำหนดเปิดใช้งานจะผูกพันlexicallyและ elided แม้สมบูรณ์หากไม่ได้ใช้ในขอบเขตของคำศัพท์ในปัจจุบัน .

รหัสเก่าบางครั้งอาศัยสิ่งนี้ เพื่อหลีกเลี่ยงการขึ้นต่อกันอย่างหนักสำหรับฟีเจอร์เสริมมันจะผูกตัวแปรแบบไดนามิกโดยไม่ต้องมีไลบรารี่ที่เกี่ยวข้องหรือประกาศตัวแปรเอง:

(let ((cook-eggs-enabled t))
  (cook-my-meal))

หากคุณลักษณะการทำอาหารเป็นตัวเลือกเราไม่ต้องการบังคับให้มีการพึ่งพาที่ไม่จำเป็นกับผู้ใช้ดังนั้นเราจึงไม่ใช้(require 'cook)และพึ่งพาcook-my-mealฟังก์ชั่นการ โหลดอัตโนมัติ

เป็นที่ชัดเจนสำหรับผู้อ่านของมนุษย์ที่cook-eggs-enabledไม่ได้เป็นตัวแปรในตัวเครื่อง แต่ยังคงอ้างถึงตัวแปรแบบไดนามิกทั่วโลกจากcookไลบรารีที่นี่ หากไม่มีlexical-bindingรหัสนี้จะทำงานตามที่ต้องการ: cook-eggs-enabledถูกผูกไว้แบบไดนามิกไม่ว่าจะถูกกำหนดไว้หรือไม่ก็ตาม

lexical-bindingอย่างไรก็ตามด้วยการแบ่งมัน: cook-eggs-enabledถูกผูกไว้กับlexically (และปรับให้เหมาะสมเนื่องจากไม่ได้ใช้) ดังนั้นตัวแปรแบบไดนามิกทั่วโลกcook-eggs-enabledจึงไม่เคยสัมผัสเลยและยัง ถูกเรียกnilตามเวลาcook-my-mealดังนั้นเราแปลกใจที่ไม่มีไข่ ในมื้ออาหารของเรา

โชคดีที่ปัญหาเหล่านี้เป็นเรื่องง่ายที่จะสังเกตเห็น : คอมไพเลอร์ไบต์ตามธรรมชาติเตือนเกี่ยวกับคำศัพท์ที่ไม่ได้ใช้ที่นี่

การแก้ไขง่ายๆคือ: ทั้งเพิ่ม(require 'cook)(สำหรับคุณสมบัติที่ไม่ได้อยู่แล้วไม่จำเป็นจริงๆ) หรือเพื่อหลีกเลี่ยงยากที่อ้างอิง-ประกาศตัวแปรเป็นตัวแปรแบบไดนามิกในรหัสของคุณเอง มีdefvarรูปแบบพิเศษสำหรับสิ่งนี้:

(defvar cook-eggs-enabled)

สิ่งนี้นิยามcook-eggs-enabledว่าเป็นตัวแปรแบบไดนามิก แต่ไม่มีผลกับ docstring, load-history(และfind-variableและเพื่อน ๆ ) หรือสิ่งอื่นใดยกเว้นลักษณะการผูกของตัวแปร


ในกรณีแบบไดนามิกข้อมูลโค้ดนั้นcook-eggs-enabledจะไม่ถูกดึงออกเมื่อทำletเสร็จหรือไม่ ฉันค่อนข้างแน่ใจว่าฉันพบข้อผิดพลาดเช่นนี้มาก่อน defvar เกิดขึ้นภายในletและletหลังจากนั้นคืนค่าตัวแปรให้เป็นสถานะเริ่มต้น (โมฆะ)
Malabarba

1
@ Malababa ไม่นั่นเป็นสถานการณ์ที่แตกต่าง ดูย่อหน้าสุดท้ายของการกำหนดตัวแปรสำหรับเหตุผล
Lunaryorn
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.