Ruby: Как отобразить функцию на хеш - PullRequest
5 голосов
/ 11 августа 2011

Я не могу понять, как назначить вызов функции хэшу ruby. То, что я хочу сделать, это назначить функцию для ключа хеша, а позже вызовите эту функцию, используя классический синтаксис хеш-поиска.

def Foo()
  puts "bar"
end

puts "Assigning"
test = { "foo" => Foo() }

puts "Executing"
test["foo"]

Этот код не работает, функция Foo вызывается после puts "Assign", во время создания хеша, и ничего не происходит после puts "Executing"

def Foo()
  puts "bar"
end

puts "Assigning"
test = { "foo" => Foo }

puts "Executing"
test["foo"]

с этим кодом я получаю uninitialized constant Foo (NameError).

Наконец с

def Foo()
  puts "bar"
end

puts "Assigning"
test = { "foo" => :Foo }

puts "Executing"
test["foo"]

Я получаю не выходные данные.

Есть предложения?

Спасибо всем за ответы и предложения.

Что я собираюсь сделать, это проверить если основанный на хэше подход к вызову функции быстрее, чем эквивалентный код, основанный на операторах if / case.

funcs["foo"].call

толстее

if func_name == "foo" then
  Foo()
elsif ...
...
end

или

case func_name
when "foo"
  Foo()
when ...
  ...
end

Очевидно, для большого количества функций (~ 150) и сотен циклы вызова

Ответы [ 4 ]

4 голосов
/ 11 августа 2011

вы можете использовать лямбда вместо методов. Два варианта здесь:

hash = {:foo => lambda { puts 'bar } }

hash[:foo].call

второе (более сложное) это:

irb(main):001:0> class Hash
irb(main):002:1>   alias :orig_anc :'[]'
irb(main):003:1>
irb(main):004:1*   def [](key)
irb(main):005:2>     if orig_anc(key).is_a? Proc
irb(main):006:3>       orig_anc(key).call
irb(main):007:3>     else
irb(main):008:3*       orig_anc(key)
irb(main):009:3>     end
irb(main):010:2>   end
irb(main):011:1> end
=> nil
irb(main):012:0> h = {:hello => 'world', :foo => lambda { puts 'bar' }}
=> {:hello=>"world", :foo=>#<Proc:0x843224c@(irb):12 (lambda)>}
irb(main):013:0> h[:hello]
=> "world"
irb(main):014:0> h[:foo]
bar
=> nil
irb(main):015:0>

Второй просто позволяет вам пропустить, используя метод 'call'

3 голосов
/ 11 августа 2011

Нет простой возможности заставить вашу функцию выполняться, просто получив хеш-ключ с переопределением метода Hash [], как указал Влад, т.е.

def foo
  puts "hi"
end

... # magic

test["foo"] # outputs hi

не будет работать. Однако вы можете назначить ссылку на метод, используя Object # method , а затем вызвать ее, используя call:

def foo
  puts "hi"
end

test = { "foo" => method(:foo) }

test["foo"].call # => hi
0 голосов
/ 11 августа 2011

Вы можете попробовать использовать хеш-конструктор с блоком, поэтому

def foo
  puts "hi"
end

test = Hash.new do |hash, key|
  send(key) if respond_to?(key)
end

test["foo"] # prints "hi", returns nil
0 голосов
/ 11 августа 2011

Перво-наперво, начинайте имена методов со строчных букв. Затем, переходя к первому примеру, Ruby стремится к тому, чтобы вызывать test = { "foo" => Foo() } Foo.

Во втором примере переменные, начинающиеся с заглавной буквы, считаются константами, поэтому Ruby ищет их и не беспокоится о поиске метода. Учтите, что если foo, где метод, то foo будет вызван, как в первом примере.

Третий пример: test["foo"] возвращает: Foo, символ. Нигде в вашем коде Foo() не вызывается.

* Предложения

1.- Посмотрите на номенклатуру идентификаторов в Ruby.

2.- Вы можете взглянуть на lambda, Proc и Object#method

3.- Если у вас есть свободные деньги и вы не против купить пару книг, дайте шанс программированию на Ruby и метапрограммированию на Ruby (обе можно купить в PragProg .

...