Ruby:如何将函数映射到哈希表?

5

我无法弄清如何将函数调用分配给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"]

使用这段代码,我收到了一个“未初始化常量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个)和数百个调用循环。

一个快速的建议 - 不要使用标题大小写定义函数; Ruby会认为它是一个常量而不是函数。 - Simon
4个回答

4

您可以使用lambda代替方法。有两个选项:

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

正如Vlad所指出的那样,如果没有覆盖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

如果这个方法需要参数呢? - svelandiag

0
你可以尝试使用带有块的哈希构造函数,如下所示:
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

首先,方法名应以小写字母开头。然后,看第一个例子,Ruby 是急切的,所以 test = { "foo" => Foo() } 会调用 Foo

在第二个例子中,以大写字母开头的变量被视为常量,因此 Ruby 会寻找一个常量,而不会去寻找一个方法。请注意,如果 foo 是一个方法,那么就像第一个例子一样,会调用 foo。

第三个例子: test["foo"] 返回 :Foo,一个符号。你的代码中没有地方调用 Foo()

*建议

1.- 查看 Ruby 中标识符的命名规则。

2.- 你可以查看 lambdaProcObject#method

3.- 如果你有一些闲钱并且不介意购买一对书,那么可以尝试购买《Programming Ruby》和《Metaprogramming in Ruby》(两本书都可以在PragProg购买)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接