2012-08-14 11 views

Odpowiedz

49

Jeśli nie konkretnie h ave być Struct a zamiast tego może być OpenStruct:

pry(main)> require 'ostruct' 
pry(main)> s = OpenStruct.new(h) 
=> #<OpenStruct a=1, b=2> 
pry(main)> puts s.a, s.b 
1 
2 
+0

Nigdy wcześniej nie słyszałem o "OpenStruct". To bardzo fajnie! Dzięki! – alf

+5

Należy pamiętać, że OpenStructs może być niezwykle powolny w użyciu. W porządku dla małej liczby małych obiektów, ale skalują się bardzo źle. Niektóre dalej informacji tutaj: http://stackoverflow.com/questions/1177594/ruby-struct-vs-openstruct –

+0

@AFaderDarkly Myślę, że ich problemy prędkości są dobrze udokumentowane, ale dzięki. –

8

Poniższa tworzy struct od mieszania w wiarygodny sposób (gdyż kolejność mieszania nie jest gwarantowana w Ruby) :

s = Struct.new(*(k = h.keys)).new(*h.values_at(*k)) 
45

Ponieważ kolejność klucz Hash jest gwarantowana w Ruby 1.9+:

Struct.new(*h.keys).new(*h.values) 
+0

Dobrze wiedzieć.Chociaż gdzieś to czytałem, ale nie pamiętałem, gdzie. Dzięki! – alf

+0

To nie działa (przynajmniej w Rubim 2.2.0): 'Struct.new (* h.keys) podnosi:' NameError: identyfikator mój_key musi być stały' – Joe

+2

@Joe działa dobrze. Myślę, że użyłeś kluczy łańcuchowych dla twojego skrótu, co jest przyczyną błędu. Błąd mówi, że potrzebuje stałej wartości, tj. Symbolu zamiast łańcucha. Mogę repro błąd w 2.1.5, odchodzi, jeśli przejdę do symbolu. – ehsanul

1

Oto przykład do mapowania wartości w odpowiedniej kolejności z struct:

require 'securerandom' 

Message = Struct.new(:to, :from, :message, :invitee) 

message_params = {from: "[email protected]", to: "[email protected]", 
     invitee: SecureRandom.uuid, message: "hello"} 

if Message.members.sort == message_params.keys.sort 
    # Do something with the return struct object here 
    Message.new *Message.members.map {|k| message_params[k] } 
else 
    raise "Invalid keys for Message" 
end 
52

Jeśli już struct zdefiniowane, a chcesz instancji wystąpienie z hash:

Person = Struct.new(:first_name, :last_name, :age) 

person_hash = { first_name: "Foo", last_name: "Bar", age: 29 } 

person = Person.new(*person_hash.values_at(*Person.members)) 

=> #<struct Person first_name="Foo", last_name="Bar", age=29> 
+0

To powinna być zaakceptowana odpowiedź :). Dzięki! – Ven

+0

Dziękujemy! Projektuję klejnot, który można wywołać z komendy lub z zewnętrznego kodu, z których każda dostarcza opcji (odpowiednio przy użyciu OptionParser lub Hash). Pozwala to na łatwe filtrowanie opcji podczas inicjalizacji mojego klejnotu. A Struct pomaga również w "samodzielnym dokumentowaniu" dozwolonych opcji! – Excalibur

-1
require 'ds_hash' 

data = {a: {b: 123 }}.to_struct 

data.a.b == 123  # true 
data.a == {b: 123 } # true 
2

Mając Hash#to_struct jest bardzo praktyczny:

class Hash 
    def to_struct 
    Struct.new(*keys).new(*values) 
    end 
end 

a niektóre przykłady:

>> { a: 1, b: 2 }.to_struct 
=> #<struct a=1, b=2> 
>> { a: 1, b: 2 }.to_struct.a 
=> 1 
>> { a: 1, b: 2 }.to_struct.b 
=> 2 
>> { a: 1, b: 2 }.to_struct.c 
NoMethodError: undefined method `c` for #<struct a=1, b=2> 

Głębokie to_struct który współpracuje z tablicami:

class Array 
    def to_struct 
    map { |value| value.respond_to?(:to_struct) ? value.to_struct : value } 
    end 
end 

class Hash 
    def to_struct 
    Struct.new(*keys).new(*values.to_struct) 
    end 
end 
+0

To dobrze, ale jeśli jego json hash '['name']', musi symbolizować klucze. – 7urkm3n

Powiązane problemy