开发者

Ruby: How to map a function to a hash

I can't figure out how to assign a function call to a ruby hash. What I want to do is to assign a function to a hash key, and later call this function using the classic hash lookout syntax.

def Foo()
  puts "bar"
end

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

puts "Executing"
test["foo"]

This code fails, function Foo is called after puts "Assign", during hash cre开发者_如何转开发ation, and nothing happens after puts "Executing"

def Foo()
  puts "bar"
end

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

puts "Executing"
test["foo"]

with this code I receive an uninitialized constant Foo (NameError).

Finally with

def Foo()
  puts "bar"
end

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

puts "Executing"
test["foo"]

I get not outputs.

Any suggestions?

Thanks to all for answres and suggestions.

What I'm going to do is to test if a hash based approach to call function is faster than an equivalent code based on if / case statements.

funcs["foo"].call

fatser than

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

or

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

Obviously for a big number of functions (~150) and hundreds of calling cycles


you could use lambda's instead of methods. Two options here:

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

hash[:foo].call

the second (more complicated) is this:

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>

The second one just allows you to skip using 'call' method


There is no easy possibility to make your function execute simply by retrieving the hash key withput overriding Hash's [] method, as Vlad pointed out, i.e.

def foo
  puts "hi"
end

... # magic

test["foo"] # outputs hi

won't work. What you can do, though, is assign the method reference using Object#method and then invoke it using call:

def foo
  puts "hi"
end

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

test["foo"].call # => hi


First things first, start method names with lower case letters. Then, moving to first example, Ruby is eager so test = { "foo" => Foo() } Foo is called.

In the second example, variables starting with an uppercase letter are considered constants, so Ruby looks for one and do not bother looking for a method. Take into account that if foo where a method then foo would be called as in the first example.

Third example: test["foo"] returns :Foo, a symbol. Nowhere in your code Foo() is invoked.

*Suggestions

1.- Take a look at identifiers nomenclature in Ruby.

2.- You may took a look at lambda, Proc and Object#method

3.- If you have some money to spare and don't mind buying a pair of books, give Programming Ruby and Metaprogramming in Ruby a chance (both can be bought in PragProg.


You could try using the hash constructor with a block, so

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜