ตัวแปรคลาสกำหนดไว้ที่ไหนใน Smalltalk?
ฉันสงสัยว่าถ้าฉันกำหนดตัวแปรคลาสใหม่เช่นสำหรับคลาสMyClass
นิยามจะอยู่ในMyClass
หรือในMyClass class
? ไม่MyClass class
ทราบเกี่ยวกับตัวแปรคลาสใหม่หรือไม่?
คำตอบ
ใช่ตัวแปรคลาสจะแชร์กับคลาสและเมตาคลาส นอกจากนี้ยังแชร์กับคลาสย่อยทั้งหมด (และเมตาคลาส) โดยปกติตัวแปรคลาสจะเป็นตัวพิมพ์ใหญ่เพื่อถ่ายทอดความคิดที่ดีกว่าในการแชร์ในขอบเขตที่กว้างกว่าคลาส คุณกำหนดตัวแปรคลาสในคลาส (ไม่ใช่เมตาคลาส)
ไม่ควรสับสนตัวแปรคลาสกับตัวแปรอินสแตนซ์คลาสซึ่งเป็นตัวแปรอินสแตนซ์ที่กำหนดในระดับเมตาคลาสเช่นตัวแปรอินสแตนซ์ของคลาสออบเจ็กต์ ความคิดนี้ค่อนข้างชัดเจนแม้จะมีความเรียบง่าย (หรือเพราะมัน): ตัวแปรเช่นมีการกำหนดไว้เสมอในชั้นเรียนเพื่อกำหนดรูปร่าง (สล็อต) กรณีของตน ดังนั้นหากเราใช้นิยามนี้กับ metaclass ซึ่งเป็นคลาสของคลาสตัวแปรอินสแตนซ์ที่กำหนดไว้ที่นี่จะกำหนดรูปร่างของอินสแตนซ์ซึ่งโดยปกติจะมีคลาสเดียว
กลับไปที่ตัวแปรคลาสคุณกำหนดไว้ในคลาส (ฝั่ง inst) และเริ่มต้นใน metaclass (เช่นฝั่งคลาส) โปรดจำไว้ว่าสิ่งเหล่านี้คือลูกโลก (บางส่วน) ในความหมายที่จะใช้ร่วมกันระหว่างอินสแตนซ์สารกลุ่มย่อยและเมตาคลาสดังนั้นจึงต้องจัดการด้วยความระมัดระวังตามปกติที่เราปฏิบัติต่อโลก
อีกหนึ่งคำชี้แจง
เมื่อเรากล่าวว่าตัวแปรอินสแตนซ์ถูกใช้ร่วมกันระหว่างอินสแตนซ์และสสารเราหมายถึงชื่อของมัน (และตำแหน่งในหน่วยความจำของช่องอ็อบเจ็กต์) เราไม่ได้หมายถึงค่าของพวกเขา (เนื้อหาของสล็อตดังกล่าว) ดังนั้นสองอินสแตนซ์ของคลาสC
จะใช้ชื่อร่วมกันcolor
เช่นถ้าคลาสกำหนด ivar color
แต่ค่าของมันในแต่ละอินสแตนซ์จะเป็นอิสระ กล่าวอีกนัยหนึ่งสิ่งที่แชร์คือชื่อไม่ใช่ค่า
ด้วยตัวแปรคลาสสิ่งที่ใช้ร่วมกันคือทั้งชื่อและค่า จริงๆแล้วมันคือAssociation
วัตถุตัวอย่างเช่นTheme -> aTheme
สิ่งที่แชร์ ดังนั้นการปรับเปลี่ยนค่าของตัวแปรคลาสจะมีผลต่อการอ้างอิงทั้งหมด นี่ไม่ใช่กรณีของตัวแปรอินสแตนซ์คลาสเนื่องจากไม่ใช่ตัวแปรอินสแตนซ์ยกเว้นว่าจะกำหนดคลาสและคลาสย่อยแทนที่จะเป็นอินสแตนซ์และสสารปกติ
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับตัวแปร Smalltalk โปรดดู https://stackoverflow.com/a/42460583/4081336
เช่นเดียวกับคำตอบของ Leandro นี่คือวิธีการเฉพาะการใช้งาน Squeak หลักที่อธิบายการแบ่งปันตัวแปรคลาสระหว่างฝั่งอินสแตนซ์ (คลาส) และฝั่งคลาส (เมตาคลาส):
Metaclass>>classPool
"Answer the dictionary of class variables."
^thisClass classPool
ที่thisClass
เป็นตัวอย่างที่ไม่ซ้ำกันของ Metaclass ที่เป็นชั้นเอง ...
มีโอกาสสูงที่จะพบการใช้งานที่คล้ายกันในภาษา Smalltalk ส่วนใหญ่
ก่อนอื่นคอมไพเลอร์จะพยายามแก้ไขตัวแปรเป็นวิธีการ / บล็อกชั่วคราว (รวมถึงพารามิเตอร์ methd / บล็อก) จากนั้นตัวแปรอินสแตนซ์จากนั้นตัวแปรที่ใช้ร่วมกัน
เมธอด classPool ถูกส่งโดยคอมไพเลอร์ในระยะสุดท้ายนี้
Leandro ได้อธิบายว่าคอมไพลเลอร์สามารถแก้ไขการผูกได้เช่นเดียวกับออฟเซ็ตที่จะถูกถอดเสียงโดยตรงใน bytecode ในกรณีของช่องตัวแปรอินสแตนซ์หรือตัวแปรวิธีการชั่วคราวหรือเป็นชนิดของการเชื่อมโยงสำหรับกรณีตัวแปรที่ใช้ร่วมกันการเชื่อมโยงนี้โดยทั่วไป เพิ่มเข้าไปในตัวอักษร CompiledMethod และใช้ร่วมกันอย่างมีประสิทธิภาพระหว่างวิธีการทั้งหมดที่จัดการกับตัวแปรนี้ (วิธีการทั้งหมดชี้ไปที่วัตถุ Assocation เดียวกันซึ่งใช้ร่วมกันได้อย่างมีประสิทธิภาพ)
ส่วนของคอมไพเลอร์เป็นภาษาถิ่นที่เฉพาะเจาะจงมากขึ้นใน Squeak ซึ่งเป็นวิธีการนี้ซึ่งใช้สำหรับการแก้ไขการเชื่อมโยงของตัวแปรที่ใช้ร่วมกัน:
class>>bindingOf: varName environment: anEnvironment
"Answer the binding of some variable resolved in the scope of the receiver"
| aSymbol binding |
aSymbol := varName asSymbol.
"First look in local classVar dictionary."
binding := self classPool bindingOf: aSymbol.
binding ifNotNil:[^binding].
"Next look in local shared pools."
self sharedPools do:[:pool |
binding := pool bindingOf: aSymbol.
binding ifNotNil:[^binding].
].
"Next look into superclass pools"
superclass ifNotNil: [^ superclass bindingOf: aSymbol environment: anEnvironment].
"No more superclass... Last look in declared environment."
^anEnvironment bindingOf: aSymbol
นี่คือการเตือนให้คุณทราบว่าส่วนที่น่าสนใจที่สุดอย่างหนึ่งของ Smalltalk คือคุณสามารถเจาะลึกการใช้งานได้จากภายใน IDE โดย Smalltalk จะเขียนใน Smalltalk เป็นหลัก!