2013-02-09 62 views
12

据我了解“发送”方法,这使用“发送”而不是普通方法调用的要点是什么?

some_object.some_method("im an argument") 

是相同的,因为这

some_object.send :some_method, "im an argument" 

那么,什么是使用“发送”方法呢?

+0

因为'send'的参数是一个符号,可以保存在一个变量中。例如,'foo =:size; [] .send foo'。虽然它可以用于访问私有方法,但IMO将其作为通用消息传递工具的用途远远超过其作为“围绕”开发人员意图的方式的价值。 – 2013-02-10 00:47:49

回答

16

如果您事先不知道方法的名称,例如在进行元编程时可以派上用场,例如,您可以将方法的名称放在变量中,并将其传递给send方法。

它也可以用来调用私有方法,尽管大多数Ruby开发人员并不认为这种特殊用法是一种很好的做法。

class Test 
    private 
    def my_private_method 
    puts "Yay" 
    end 
end 

t = Test.new 

t.my_private_method # Error 

t.send :my_private_method #Ok 

您可以使用public_send,但只能调用公共方法。

+8

第二个用例远比第一个更重要,IMO。 – 2013-02-10 00:45:15

+4

如果您的唯一意图是动态调用,则可以使用'public_send'。 – 2013-02-10 02:41:44

+0

使用send不是一个不好的做法。 – christianblais 2013-02-10 06:43:58

5

除了Intrepidd的用例外,当您想要在同一个接收器和/或参数上路由不同的方法时,这很方便。如果你有some_object,并要根据什么foo是,则没有send就可以做不同的事情,你需要写,如:

case foo 
when blah_blah then some_object.do_this(*some_arguments) 
when whatever then some_object.do_that(*some_arguments) 
... 
end 

但如果你有send,你可以写

next_method = 
case foo 
when blah_blah then :do_this 
when whatever then :do_that 
.... 
end 
some_object.send(next_method, *some_arguments) 

some_object.send(
    case foo 
    when blah_blah then :do_this 
    when whatever then :do_that 
    .... 
    end, 
    *some_arguments 
) 

或通过使用散列,即使这样的:

NextMethod = {blah_blah: :do_this, whatever: :do_that, ...} 
some_object.send(NextMethod[:foo], *some_arguments) 
0

简要总结了同事已经说过的内容:send方法是一种用于元编程的语法糖。下面的例子演示时,方法本地通话是可能不可能的情况下:

class Validator 
    def name 
    'Mozart' 
    end 
    def location 
    'Salzburg' 
    end 
end 

v = Validator.new 
'%name% was born in %location%'.gsub (/%(?<mthd>\w+)%/) do 
    # v.send :"#{Regexp.last_match[:mthd]}" 
    v.send Regexp.last_match[:mthd].to_sym 
end 
=> "Mozart was born in Salzburg" 
-1

我喜欢这个巷道施工

Object.get_const("Foo").send(:bar) 
4

除了别人的答案,一个良好的用例是通过方法迭代包含一个递增数字。

class Something 
    def attribute_0 
    "foo" 
    end 
    def attribute_1 
    "bar" 
    end 
    def attribute_2 
    "baz" 
    end 
end 

thing = Something.new 

3.times do |x| 
    puts thing.send("attribute_#{x}") 
end 

#=> foo 
# bar 
# baz 

这可能看起来微不足道,但它偶尔帮助我保持我的Rails代码和模板干爽。这是一个非常具体的案例,但我认为这是一个有效的案例。

+0

我会说任何取决于增加数字的命名都是严重的代码异味。上面的类可能需要像def属性这样的方法; [“foo”,“bar”,“baz”]; end'。 – 2016-01-22 12:23:08

+0

你说得对。当时我是个白痴。但显然,发送仍然有其作为元编程工具的地位。 – Ravenstine 2016-01-22 16:54:10

+0

要清楚:我从来没有称你为白痴,也不认为你是一个白痴。你的'send'的例子是完全有效的,但希望额外的洞察力可以用于没有经验的未来读者。 – 2016-01-22 16:56:38

相关问题