Nhận giá trị của một biến thể hiện với tên của nó


99

Nói chung, làm cách nào tôi có thể lấy tham chiếu đến một đối tượng mà tôi có tên trong một chuỗi?

Cụ thể hơn, tôi có một danh sách các tên tham số (các biến thành viên - được xây dựng động nên tôi không thể tham khảo trực tiếp).

Mỗi tham số là một đối tượng cũng có một from_sphương thức.

Tôi muốn làm điều gì đó như sau (tất nhiên là không hoạt động ...):

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

Câu trả lời:


179

Cách thành ngữ nhất để đạt được điều này là:

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

Không có nhu cầu sử dụng +hoặc intern; Ruby sẽ xử lý tốt việc này. Tuy nhiên, nếu bạn thấy mình đang chạm vào một đối tượng khác và kéo ra ivar của nó, rất có thể bạn đã phá vỡ tính năng đóng gói.

Nếu bạn muốn truy cập rõ ràng một ivar, điều đúng đắn cần làm là biến nó thành một trình truy cập. Hãy xem xét những điều sau:

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

Trong trường hợp này, nếu bạn làm vậy Computer.new, bạn sẽ buộc phải sử dụng instance_variable_getđể đạt được @cpus. Nhưng nếu bạn đang làm điều này, bạn có thể muốn @cpuscông khai. Điều bạn nên làm là:

class Computer
  attr_reader :cpus
end

Bây giờ bạn có thể làm Computer.new(4).cpus.

Lưu ý rằng bạn có thể mở lại bất kỳ lớp nào hiện có và tạo ivar riêng tư thành trình đọc. Vì trình truy cập chỉ là một phương pháp, bạn có thể làmComputer.new(4).send(var_that_evaluates_to_cpus)


Instance_variable_get ("@ # {name}") không trả về giá trị của biến? Tôi cần tham chiếu đến đối tượng thực tế. Tôi đã kết thúc việc viết lại vì vậy thay vì có nhiều biến + một mảng có tên theo thứ tự tôi muốn, tôi đặt chính các tham số vào mảng (quyết định thiết kế là truy cập các biến mỗi lần bằng cách tìm kiếm mảng hay tối ưu hóa bằng cách có mảng bổ sung với tên của chúng sẽ chỉ được sử dụng khi cần thiết)
LK__

Nope: instance_variable_get ("@ # {name}") trả về đối tượng thực tế.
Yehuda Katz

Khám phá sợi dây chết chóc cho một chút rõ ràng. Ví dụ hoàn chỉnh sẽ là: class Computer attr_read: cpus def new (cpus) @cpus = cpus end end?
Nicolas de Fontenay

"Tuy nhiên, nếu bạn thấy mình đang thò tay vào một đối tượng khác và kéo ra ivar của nó, thì rất có thể bạn đã phá vỡ sự đóng gói.". Làm thế nào để chúng ta đột nhập vào ivar của đối tượng khác ?.
RubyMiner

9

Để lấy một biến thể hiện từ tên của một biến thể hiện, hãy làm:

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

Điều này sẽ trả về giá trị của biến cá thể @paramName


Trong khi tạo động một lớp, tôi có một mảng tên biến cá thể (tôi cần danh sách này vì tôi cần xử lý chúng theo một thứ tự nhất định). Bằng cách sử dụng tên này, tôi muốn nhận một tham chiếu đến biến.
LK__

1
Tôi có một chuỗi "paramName" và cần tham chiếu đến @paramName
LK__

1
ĐỒNG Ý. Tôi khuyên bạn nên chỉnh sửa câu hỏi của mình để nói chính xác hai nhận xét đó.
Daniel Lucraft

2
Ngoài ra, điều này không liên quan gì đến quá trình deserialization. Tiêu đề tốt hơn có thể là "Lấy giá trị của một biến thể hiện với tên của nó" hoặc một cái gì đó.
Daniel Lucraft

Bạn luôn có thể thực hiện một Mô-đun và thêm :attr_reader varnameđể sau đó bạn có thể truy cập các biến theo cách gọn gàng hơn, ít dài dòng hơn.
ocodo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.