`setq-local 'ทำอะไรและฉันควรใช้เมื่อใด


16

ฉันไม่ชัดเจนเกี่ยวกับรูปแบบทั้งหมดของตัวแปรบัฟเฟอร์ภายในแม้ว่าหลังจากอ่านเอกสารทั้งหมดและการโพสต์มากมายที่นี่ใน SX

นี่คือบทสรุปของความเข้าใจของฉัน:

(defvar foo ..)ประกาศตัวแปรแบบไดนามิกสำหรับไฟล์ แต่ตัวแปรคือ (1) ไม่รู้จักไฟล์อื่นนอกจากว่าพวกเขาจะมีdefvar คำสั่งเช่นกันและ (2) ตัวแปรนั้นเป็นโกลบอลในขอบเขตไม่ใช่บัฟเฟอร์ในเครื่อง

(make-variable-buffer-local foo)หลังจากที่defvarด้านบนบอกคอมไพเลอร์และทุกคนอื่นว่าตัวแปร foo นั้นจะได้รับการปฏิบัติเสมือนบัฟเฟอร์ในทุก ๆ ที่มันถูกตั้งค่าเมื่อมันถูกตั้งค่า ดังนั้นรูปแบบนี้เป็นรูปแบบที่ดีสำหรับการประกาศตัวแปรบัฟเฟอร์ในเครื่องโดยวางทั้งสองข้อความกลับไปด้านหลัง

(defvar xxx ...)                    ;declare xxx with global scope
(make-variable-buffer-local 'xxx)   ;but now make it buffer-local everywhere

เพื่อความสะดวก(defvar-local xxx ...)แบบฟอร์มสามารถใช้เป็นหนึ่งบรรทัดแทนที่สองบรรทัดด้านบน:

(defvar-local xxx ...)       ;make xxx buffer local everywhere

เมื่อประกาศไว้ข้างต้นตัวแปร xxx สามารถใช้เหมือนกับตัวแปรอื่น ๆ ในคำสั่ง setq

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

(defvar xxx ...)             ;declare xxx with global scope
(make-local-variable 'xxx)   ;make xxx local in this buffer only

ตอนนี้สำหรับคำถามที่อธิบายของฉัน (ทั้งหมดข้างต้นเป็นคำถามโดยนัยว่าความเข้าใจของฉันถูกต้องหรือไม่)

เมื่อตั้งค่าของตัวแปรที่ฉันสามารถใช้หรือsetq setq-localควรsetq-localใช้เมื่อใด ทำไม?

จะเกิดอะไรขึ้นถ้าฉันใช้setq-localกับ vars บัฟเฟอร์ภายในเครื่องหรือไม่ใช่ vars บัฟเฟอร์ภายในเครื่อง

เป็นที่setq-localจำเป็นสำหรับการdefvar-localประกาศตัวแปร?

จะsetq-localอยู่บนปกติdefvarตัวแปรประกาศเปิดเป็นตัวแปรบัฟเฟอร์ท้องถิ่น? (ในคำอื่น ๆsetq-localอย่างใดเทียบเท่าของการ(make-variable-local xxx)ประกาศหรือไม่


ขอบคุณสำหรับแรงงานพิเศษสกอตต์ ฉันจะใส่ backquotes พิเศษจากตรงนี้ลงไป
เควิน

2
(setq-local VAR VALUE)เป็นเพียงการจดชวเลข(set (make-local-variable VAR) VALUE)ซึ่งเป็น (และยังคงเป็น) สำนวนร่วมกัน
Drew

คำตอบ:


18

สมมติฐานส่วนใหญ่ของคุณอยู่ใกล้ ฉันจะพูดถึงไม่กี่ภายหลัง แต่ก่อนอื่นคำถามหลัก

แบบฟอร์มที่setq-localเป็นเพียงความสะดวกสบายก็เป็นเช่นเดียวกับการทำตามด้วยmake-local-variable setqหากคุณได้ทำC-h f setq-localเพื่อดูเอกสารและคลิกไปยังแหล่งที่คุณอาจได้เห็นสิ่งนี้ นั่นเป็นวิธีที่ฉันยืนยันความประทับใจครั้งแรกของฉัน รหัสนั้นค่อนข้างคลุมเครือเล็กน้อยเนื่องจากมันเป็นการปรับให้เหมาะสมกับสิ่งต่าง ๆ เช่นความจริงที่ว่าmake-local-variableจริง ๆ แล้วส่งคืนตัวแปรเอง การใช้setq-localเป็นวิธีที่จะชี้ให้เห็นความเป็นท้องถิ่นในบางโค้ดเพื่อให้คนอื่นรู้ว่าโค้ดไม่สามารถเล่นได้ด้วยค่าโกลบอลของตัวแปร คุณไม่จำเป็นต้องใช้มันเพื่อเข้าถึงตัวแปรท้องถิ่น ตัวแปรใด ๆ สามารถทำบัฟเฟอร์แบบโลคัลและที่จะมีผลกับโค้ดทั้งหมดที่สัมผัสกับตัวแปร (ยกเว้นว่ามันจะออกนอกเส้นทางเพื่อรับสำเนาทั่วโลกด้วยsetq-defaultหรือคล้ายกัน)

นั่นคือคำตอบหลัก ตอนนี้มีบางสิ่งในพื้นหลังของคุณที่ปิดอยู่เล็กน้อย เมื่อคุณถามถึงเรื่องนี้ฉันจะพูดอะไรบางอย่าง

ที่แรกก็คือ "ไม่รู้จักไฟล์อื่น ๆ " นี่ไม่เป็นความจริงเลย รหัสใด ๆ สามารถอ้างอิงตัวแปรทั่วโลกใด ๆ (นั่นคือสาเหตุที่พวกเขาถูกเรียกว่า "ทั่วโลก") โดยไม่ต้องรวมdefvar(และC-h f defvarพูดอย่างนั้น) ที่จริงแล้วควรมีเพียงหนึ่งหลักdefvar(ที่มี docstring และค่าเริ่มต้น) สำหรับตัวแปรกลางแต่ละตัว A ที่defvarมีเพียงชื่อตัวแปรเท่านั้นที่สามารถใช้เพื่อยับยั้งการเตือน byte-compiler Emacs ใช้ค่าจากค่าแรกที่เห็นเท่านั้นและ docstring จากค่าล่าสุด หากมีหลายdefvars ที่มีค่า / docstring พวกเขาอาจสร้างความสับสนให้กับคนที่อ่านรหัส และลำดับของการโหลดไฟล์จะมีความสำคัญ

ตัวแปรบางตัวมีวัตถุประสงค์เพื่อใช้เป็นบัฟเฟอร์ในเครื่องเท่านั้นและเป็นตัวแปรที่ใช้defvar-local(หรือสองส่วนdefvar/ make-variable-buffer-localซึ่งย่อให้โดยส่วนใหญ่อยู่ในรหัสเก่าก่อนที่จะเพิ่มรูปแบบย่อ) สิ่งนี้ทำให้มันเป็นบัฟเฟอร์ท้องถิ่นในบัฟเฟอร์ทั้งหมด สำหรับตัวแปรบางตัวการใช้งานหลักไม่ใช่บัฟเฟอร์ในตัวเครื่อง แต่ด้วยเหตุผลบางประการคุณอาจต้องการให้บัฟเฟอร์หนึ่งตัวมีค่าแตกต่างกัน นั่นคือเมื่อคุณใช้งานmake-local-variableมักจะอยู่ในรหัสการตั้งค่าบัฟเฟอร์บางอย่างแทบจะไม่ถูกต้องdefvarเลย

และโดยทั่วไปมีสองวัตถุประสงค์ในdefvarแบบฟอร์ม หนึ่งคือการมีเอกสารบางอย่างเพื่อให้ผู้อื่นC-h vสามารถใช้รู้ว่าตัวแปรนั้นมีไว้เพื่ออะไร ที่สองคือการประกาศค่า "เริ่มต้น" เพื่อให้ตัวแปรถูกตั้งค่าเสมอ การประกาศค่าเริ่มต้นมีผลกับอินสแตนซ์ส่วนกลาง (หรือค่าเริ่มต้น) ของตัวแปรเท่านั้นและจะใช้เฉพาะเมื่ออินสแตนซ์นั้นไม่ได้ถูกตั้งค่าเป็นบางอย่าง นั่นหมายความว่าถ้าคุณsetqมีตัวแปรแล้วรวมไฟล์ด้วยdefvar(เช่นผ่าน a require), defvar จะไม่เปลี่ยนค่า

¹ อย่างแม่นยำมากขึ้นdefvarไม่ได้ปรับเปลี่ยนค่าของตัวแปรถ้ามันกำหนดไว้แล้ว (มันไม่ตั้ง docstring แต่); สิ่งนี้มีความหมายเพื่อให้ไฟล์เริ่มต้นของผู้ใช้สามารถทำได้(setq some-variable)ก่อนที่จะโหลดแพคเกจเพื่อแทนที่ค่าเริ่มต้นของแพ็คเกจ


1
ขอบคุณสำหรับคำตอบที่ชัดเจนมากมันช่วยได้มาก เมื่อฉันใช้วลี "ไม่รู้จักไฟล์อื่น ๆ " ฉันคิดว่าคำเตือนตัวแปรอิสระเพราะไฟล์อื่น ๆ เหล่านั้นจะคิดว่าตัวแปรนั้นฟรียกเว้นว่าฉันจะเพิ่ม defvar ลงไป ฉันชอบคำสั่งของคุณที่set-localบอกผู้อ่านว่ามีการตั้งค่า var ท้องถิ่น ทุกสิ่งที่ฉันสามารถทำได้เพื่อปรับปรุงการอ่านโค้ดของฉันนั้นดี! PS ฉันจะพยายามคลิกผ่านไปยังแหล่งข้อมูลบ่อยขึ้น ที่ระดับการพัฒนาปัจจุบันของฉันมันมักจะไม่ได้รับความหมาย ... :-)
Kevin

1
"ควรมีเพียงหนึ่งรายการdefvarสำหรับตัวแปรส่วนกลางแต่ละตัว" ไม่ถูกต้องอย่างเคร่งครัด - มีสถานการณ์เมื่อ(defvar VARNAME) ไม่มีการประกาศค่าที่ควรเป็นอิสระจากคำจำกัดความที่เหมาะสม (ด้วยค่าเริ่มต้นและ docstring) ของ VARNAME นั้น
phils

2
ยังทราบว่าsetq-localและdefvar-localถูกนำมาใช้เฉพาะใน Emacs 24.3
phils

1
@phils คุณช่วยกรุณาระบุสถานการณ์ที่คุณพูดถึงซึ่ง(defvar varname)ควรจะประกาศที่ไหนโดยไม่มีค่า ฉันคิดว่านั่นคือสิ่งที่ Drew แนะนำในหัวข้ออื่นเมื่อฉันถูกถามว่าจะกำจัดคำเตือนตัวแปรฟรีในไฟล์ของฉันสำหรับ globals ฉันได้ประกาศไว้ที่อื่น ฉันทำอย่างนั้นตอนนี้ นั่นคือสถานการณ์ที่คุณพูดถึง?
Kevin

1
การหลีกเลี่ยงคำเตือนการรวบรวมไบต์เป็นเหตุผลหนึ่งที่ใช่ (ดูC-h i g (elisp) Warning Tips) อีกอันสำหรับไลบรารีที่ใช้การเชื่อมคำศัพท์เพื่อให้แน่ใจ (ถ้าจำเป็น) ว่าตัวแปรนั้นถูกผูกไว้แบบไดนามิกแทนที่จะถูกผูกมัดด้วยคำศัพท์
phils
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.