2012-11-14 30 views
13

Nói rằng tôi có băm này:của Ruby giá trị lần lượt bên trong một băm vào các biến địa phương

entry = {"director"=>"Chris Nolan", "prducer"=>"Sum Duk", "writer"=>"Saad Bakk"} 

tôi muốn trích xuất mỗi chìa khóa vào biến cục bộ riêng của mình với các giá trị liên quan đến:

director = "Chris Nolan" 
producer = "Sum Duk" 
... 

Bằng cách sử dụng một vòng lặp và không:

director = entry["director"] 

Vì có nhiều giá trị và tôi không muốn làm riêng chúng.

Tôi thấy điều này hoạt động gần như hoàn hảo ngoại trừ nó tạo ra biến mẫu và tôi muốn biến cục bộ, nhưng local_variable_set không tồn tại vì một số lý do.

entry.each_pair { |k, v| instance_variable_set("@#{k}", v) } 

Có giải pháp nào không? Hoặc thất bại đó, một cách để biến một biến thể hiện thành một biến cục bộ và xóa một cá thể mà không làm từng cái một?

+0

Bất kỳ lý do họ không thể ở trong băm và được truy cập từ đó? Có lẽ, bạn đang sử dụng các biến cục bộ sau này - nó sẽ không dễ sử dụng các giá trị băm? – Pavling

+0

Nếu bạn đang sử dụng Rails (hoặc chỉ ActiveSupport), bạn có thể sử dụng một lớp lót sau: 'director, producer, writer = entry.values_at ('director', 'producer', 'writer')'. Thật không may là bạn phải gõ từng tên biến hai lần (thay vì 0 lần khi bạn yêu cầu), nhưng nó vẫn là cách súc tích nhất mà tôi đã tìm thấy để làm điều này. – antinome

+0

có thể trùng lặp của [Cách tạo động một biến cục bộ?] (Http://stackoverflow.com/questions/18552891/how-to-dynamically-create-a-local-variable) – Ajedi32

Trả lời

2

Bạn không thể tạo biến cục bộ, vì phạm vi biến.
Nếu bạn tạo biến cục bộ bên trong một khối, biến sẽ chỉ có thể truy cập bên trong chính khối đó.
Vui lòng tham khảo câu hỏi này để biết thêm thông tin.
Dynamically set local variables in Ruby

+0

Điều đó có ý nghĩa, nhưng rất buồn . Tôi đoán tôi đang bị mắc kẹt bằng cách sử dụng các biến dụ hoặc làm điều đó bằng tay: ( – kakubei

+0

Thật vậy, tôi đoán rằng một số dòng trong mã là con đường để đi. – MurifoX

4

Bạn có thể làm điều này với eval, nhưng tất cả các hoạt động trên các biến phải được bên trong phạm vi họ đã được định nghĩa trong

Ví dụ, điều này sẽ làm việc:.

vals = { 
    "foo" => "bar", 
    "baz" => "qux" 
} 

eval <<-EOF 
    #{ vals.map {|k, v| "#{k} = \"#{v}\""}.join("\n") } 
    puts foo 
EOF 

Tuy nhiên, điều này sẽ không:

vals = { 
    "foo" => "bar", 
    "baz" => "qux" 
} 

eval <<-EOF 
    #{ vals.map {|k, v| "#{k} = \"#{v}\""}.join("\n") } 
EOF 

puts foo 

như foo vượt quá phạm vi tại t ông kết thúc của eval. Tuy nhiên, nếu tất cả công việc của bạn trên các biến có thể được thực hiện bên trong phạm vi của eval, nó khá khả thi.

+0

@kakubei: Chính xác, trong Ruby bạn có thể vượt qua hầu hết mọi ràng buộc. Mặc dù cái bạn chọn - biến cục bộ - hơi khó, nhưng biến cục bộ chỉ có nghĩa là sử dụng trong thời gian ngắn –

+0

Điều đó không thực sự hiệu quả đối với băm bằng các phím không phải chuỗi (hoặc có thể xâu chuỗi). – Hut8

2

Lựa chọn 1

Tôi không thể khuyên này trừ cho vui, nhưng nó chủ yếu có tác dụng bạn đang sau:

entry.each |k, v| 
    singleton_class.send(:attr_accessor, k) 
    send("#{k}=", v) 
end 

director      # => "Chris Nolan" 
self.director = "Wes Anderson" # Unfortunately, must use self for assignment 
director      # => "Wes Anderson" 

Thay vì tạo ra các biến cục bộ nó định nghĩa phương pháp acccessor trên lớp singleton của đối tượng hiện tại, mà bạn có thể gọi như thể chúng là các biến cục bộ.

Để làm cho chúng "địa phương" hơn, bạn có thể sử dụng singleton_class.remove_method để loại bỏ các phương pháp này khi bạn đang thực hiện với chúng. Bạn thậm chí có thể cố gắng để bí danh bất kỳ phương thức lớp singleton hiện có với cùng tên và khôi phục chúng sau đó.

Lựa chọn 2

Đây là điều mà tôi sử dụng trong mã thực. Nó đòi hỏi đá quý ActiveSupport đi kèm với Ruby On Rails nhưng cũng có thể được sử dụng riêng của nó.

director, producer, writer = entry.values_at('director', 'producer', 'writer') 

Thật không may, nó yêu cầu nhập từng tên biến hai lần thay vì 0 lần như bạn đã yêu cầu. Nếu bạn đã chắc chắn về thứ tự của các giá trị trong băm, bạn có thể viết:

director, producer, writer = entry.values # Not so good, IMO. 

tôi cảm thấy không thoải mái về phiên bản này bởi vì bây giờ mã đã tạo ra băm có trách nhiệm không rõ ràng để đảm bảo băm là theo một thứ tự nhất định.

Note

Nếu mục tiêu của bạn chỉ là để giảm đánh máy, đây là một cách tiếp cận mà chỉ yêu cầu hai nhân vật nhiều hơn mỗi truy cập biến hơn nếu họ thật sự biến cục bộ:

e = OpenStruct.new(entry) 
e.director  # => "Chris Nolan" 
Các vấn đề liên quan