2012-03-15 11 views
6

Mam dwa przykłady, które dają taki sam wynik.Kiedy bloki są bardziej przydatne niż funkcje (ruby)?

Z bloku:

def self.do_something(object_id) 
    self.with_params(object_id) do |params| 
    some_stuff(params) 
    end 
end 

def self.with_params(object_id, &block) 
    find_object_by_id 
    calculate_params_hash 
    block.call(params_hash) 
end 

i metody:

def self.do_something(object_id) 
    some_stuff(self.get_params(object_id)) 
end 

def self.get_params(object_id) 
    find_object_by_id 
    calculate_params_hash 
    params_hash 
end 

Drugie rozwiązanie wydaje się proste, ale znalazłem kilka zwyczaje pierwsza w naszym kodzie aplikacji. Moje pytanie brzmi: w jakiej sytuacji zaleca się pierwszą? Jakie są plusy i minusy każdego z nich?

+0

W twoim przykładzie nie wierzę, że istnieje powód do używania obiektu Proc. Cały obiekt obiektów Proc polega na utrzymywaniu ich w środowisku leksykalnym i przekazywaniu ich do innych funkcji jako argumentów. –

+0

dodał "proc" jako tag. –

+0

Co robi 'some_stuff (params)', czy zwraca coś? – nkm

Odpowiedz

2

Główną różnicą pomiędzy blokiem i funkcji, jak na swój przykład to, że blok biegnie w kontekście funkcji wywołującej.

Więc jeśli przykładem jak:

def self.do_something(object_id) 
    x = "boogy on" 
    self.with_params(object_id) do |params| 
    some_stuff(params) 
    puts x 
    end 
end 

Kod w bloku może uzyskać dostęp do zmiennej x, która została zdefiniowana poza blokiem. Nazywa się to zamknięciem. Nie mógłbyś tego zrobić, gdybyś tylko wywoływał funkcję, jak na twój drugi przykład.

Inną interesującą rzeczą dotyczącą bloków jest to, że mogą wpływać na przepływ sterowania funkcją zewnętrzną.Tak więc możliwe jest wykonanie:

def self.do_something(object_id) 
    self.with_params(object_id) do |params| 
    if some_stuff(params) 
     return 
    end 
    end 

    # This wont get printed if some_stuff returns true. 
    puts "porkleworkle" 
end 

Jeśli wywołanie some_stuff w bloku zwróci wartość true, blok zostanie zwrócony. Spowoduje to wyjście z bloku i wyjście z metody dawometulacji. porkleworkle nie otrzyma danych wyjściowych.

W swoich przykładach nie polegasz na żadnej z nich, więc używanie funkcji jest prawdopodobnie znacznie czystsze.

Jednak istnieje wiele sytuacji, w których używanie bloków do korzystania z tych funkcji jest nieocenione.

3

Zwykle ludzie używają bloków, gdy chcą uruchomić fragment kodu wewnątrz innego fragmentu kodu. Przykłady:

DB.with_shard_for_user(user_id) do |db| 
    # perform operations on a user's shard 

end # shard is reverted back to original value 

File.new(filename) do |file| 
    # work with file 
end # file is closed automatically 

User.transaction do 
    # run some operations as a single transaction 
end 

Bloki te są zamknięte w ich kontekście leksykalnym (one przechwytywać zmienne z którym blok jest zadeklarowana i przenosić je na miejscu, gdy bloki są nazywane).

Schematyczna struktura metody akceptującej blok.

def transaction 
    open_transaction # pre- part 

    yield if block_given? # run provided code 

    commit_transaction # post- part 
rescue 
    rollback_transaction # handle problems 
end 

W pierwszym przykładzie użycie bloku jest prawdopodobnie nieuzasadnione (IMHO). Zbyt skomplikowane bez wyraźnego powodu.

1

Podczas wywoływania funkcji with_params() wysyłane są nie tylko dane, ale także kod do uruchomienia. Zobacz, czy różne bloki są wysyłane do with_params() zadzwonić:

... 
self.with_params(object_id) do |params| 
    some_other_stuff() 
    some_stuff(params) 
end 
... 

i gdzie indziej:

... 
self.with_params(object_id) do |params| 
    even_more_stuff(params) 
end 
... 

Jeśli bloki są wszystkie takie same lub with_params() jest nazywany po prostu z jednego miejsca wtedy może rozważyć wyeliminowanie bloków.

Podsumowując: użyj bloków, jeśli chcesz przekazać do metody różne bity kodu (bloki), a także dane: hej with_params, weź te dane (object_id), a przy okazji uruchom ten kod (blok) podczas gdy ty jesteś w tym.

BTW robisz różne rzeczy w tych dwóch przykładach: with_params() zwraca

some_stuff(params_hash) 

po ocenie bloku. I get_params() po prostu zwraca

params_hash 
1

Blok całkowicie polega na kodzie, ale funkcja ma swój własny kod.

Jeśli więc twój kod różni się w zależności od sytuacji, użyj bloku. Jeśli nie, utwórz funkcję i użyj jej jako bloku bloków.

Powiązane problemy