รับค่าของตัวแปรอินสแตนซ์ที่กำหนดชื่อ


99

โดยทั่วไปฉันจะอ้างอิงถึงวัตถุที่มีชื่อในสตริงได้อย่างไร

โดยเฉพาะอย่างยิ่งฉันมีรายการชื่อพารามิเตอร์ (ตัวแปรสมาชิก - สร้างขึ้นแบบไดนามิกดังนั้นฉันจึงไม่สามารถอ้างถึงโดยตรงได้)

พารามิเตอร์แต่ละตัวเป็นออบเจ็กต์ที่มีไฟล์ from_sวิธีการ

ฉันต้องการทำสิ่งต่อไปนี้ (ซึ่งแน่นอนว่าไม่ได้ผล ... ):

define_method(:from_s) do | arg |
    @ordered_parameter_names.each do | param |
        instance_eval "field_ref = @#{param}"
        field_ref.from_s(param)
    end
end

คำตอบ:


179

วิธีที่ง่ายที่สุดในการบรรลุสิ่งนี้คือ:

some_object.instance_variable_get("@#{name}")

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

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

class Computer
  def new(cpus)
    @cpus = cpus
  end
end

ในกรณีนี้หากคุณไม่Computer.newคุณจะถูกบังคับให้ใช้ที่จะได้รับinstance_variable_get @cpusแต่ถ้าคุณกำลังทำสิ่งนี้คุณอาจหมายถึง@cpusต้องการเปิดเผยต่อสาธารณะ สิ่งที่คุณควรทำคือ:

class Computer
  attr_reader :cpus
end

ตอนนี้คุณสามารถทำได้ Computer.new(4).cpusตอนนี้คุณสามารถทำ

โปรดทราบว่าคุณสามารถเปิดการใด ๆในชั้นเรียนที่มีอยู่และทำให้ Ivar ส่วนตัวเข้าสู่ผู้อ่าน เนื่องจาก accessor เป็นเพียงวิธีการหนึ่งคุณสามารถทำได้Computer.new(4).send(var_that_evaluates_to_cpus)


ไม่ instance_variable_get ("@ # {name}") ส่งคืนค่าของตัวแปรใช่หรือไม่ ฉันต้องการการอ้างอิงถึงวัตถุจริง ฉันลงเอยด้วยการเขียนใหม่ดังนั้นแทนที่จะมีตัวแปรหลายตัว + อาร์เรย์ที่มีชื่อตามลำดับที่ฉันต้องการฉันใส่พารามิเตอร์ลงในอาร์เรย์ (การตัดสินใจในการออกแบบคือว่าจะเข้าถึงตัวแปรในแต่ละครั้งโดยการค้นหาอาร์เรย์หรือปรับให้เหมาะสมโดยมี อาร์เรย์เพิ่มเติมพร้อมชื่อที่จะใช้เมื่อจำเป็นเท่านั้น)
LK__

Nope: instance_variable_get ("@ # {name}") ส่งคืนวัตถุจริง
Yehuda Katz

เปิดโปงกระทู้ที่ตายแล้วให้กระจ่างสักหน่อย ตัวอย่างที่สมบูรณ์จะเป็น: class Computer attr_read: cpus def new (cpus) @cpus = cpus end end?
Nicolas de Fontenay

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

9

ในการรับตัวแปรอินสแตนซ์จากชื่อของตัวแปรอินสแตนซ์ให้ทำ:

name = "paramName"
instance_variable_get(("@" + name).intern)

สิ่งนี้จะส่งคืนค่าของตัวแปรอินสแตนซ์ @paramName


ในขณะที่สร้างคลาสแบบไดนามิกฉันมีอาร์เรย์ของชื่อตัวแปรอินสแตนซ์ (ฉันต้องการรายการนี้เพราะต้องจัดการตามลำดับที่แน่นอน) เมื่อใช้ชื่อนี้ฉันต้องการได้รับการอ้างอิงถึงตัวแปร
LK__

1
ฉันมีสตริง "paramName" และต้องการข้อมูลอ้างอิงถึง @paramName
LK__

1
ตกลง. ฉันขอแนะนำให้คุณแก้ไขคำถามเพื่อให้พูดความคิดเห็นทั้งสองนั้นได้
Daniel Lucraft

2
นอกจากนี้สิ่งนี้ไม่เกี่ยวข้องกับ deserialization ชื่อที่ดีกว่าอาจเป็น "รับค่าของตัวแปรอินสแตนซ์ที่กำหนดชื่อ" หรืออะไรก็ได้
Daniel Lucraft

คุณสามารถสร้างโมดูลและเพิ่มได้ตลอดเวลา:attr_reader varnameเพื่อให้คุณสามารถเข้าถึงตัวแปรในลักษณะที่สะอาดและละเอียดน้อย
ocodo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.