Send()在 Ruby 中做什么?

谁能告诉我下面的片段

obj.send("#{method_name}")

现在和将来?

129081 次浏览

Send 是一个 Ruby 方法,它允许通过名称传递任何指定的参数来调用另一个方法。

 class Klass
def hello(*args)
"Hello " + args.join(' ')
end
end
k = Klass.new
k.send :hello, "gentle", "readers"   #=> "Hello gentle readers"

来源

send向对象实例及其在类层次结构中的祖先发送消息,直到某个方法作出反应(因为它的名称与第一个参数匹配)。

实际上,这两句话是等价的:

1.send '+', 2
1.+(2)
1 + 2

请注意,send绕过了可见性检查,因此您也可以调用私有方法(对于单元测试很有用)。


如果在发送之前确实没有变量,这意味着使用了全局对象:

send :to_s    # "main"
send :class   # Object

这是我认为最有用的特性之一。Send 方法是它可以动态调用。这可以为您节省大量的打字工作。最流行的用法之一。Send 方法是动态分配属性。例如:

class Car
attr_accessor :make, :model, :year
end

为了定期分配属性,需要

c = Car.new
c.make="Honda"
c.model="CRV"
c.year="2014"

或者使用. send 方法:

c.send("make=", "Honda")
c.send("model=", "CRV")
c.send("year=","2014")

但它们都可以被以下内容所取代:

假设您的 Rails 应用程序需要从用户输入中为您的汽车类分配属性,那么您可以这样做

c = Car.new()
params.each do |key, value|
c.send("#{key}=", value)
end

另一个例子,类似于安东尼奥 · 杰哈的 https://stackoverflow.com/a/26193804/1897857

是否需要读取对象的属性。

例如,如果您有一个字符串数组,如果您尝试遍历它们并在对象上调用它们,那么它将无法工作。

atts = ['name', 'description']
@project = Project.first
atts.each do |a|
puts @project.a
end
# => NoMethodError: undefined method `a'

但是,您可以 send对象的字符串:

atts = ['name', 'description']
@project = Project.first
atts.each do |a|
puts @project.send(a)
end
# => Vandalay Project
# => A very important project

视图的另一个用例:

    <%= link_to
send("first_part_of_path_#{some_dynamic_parameters}_end_path",
attr1, attr2), ....
%>

允许您编写可伸缩的视图,这些视图可以处理所有类型的对象 与:

    render 'your_view_path', object: "my_object"

发送是做什么的?

send是“调用方法”的另一种方式,例如:

o = Object.new
o.to_s # => "#<Object:0x00005614d7a24fa3>"
# is equivalent to:
o.send(:to_s) # => "#<Object:0x00005614d7a24fa3>"

Send 生活在 Object 类 中。

这样做有什么好处?

这种方法的好处是可以将要调用的方法作为参数传入。下面是一个简单的例子:

def dynamically_call_a_method(method_name)
o = Object.new
o.send method_name
end
dynamically_call_a_method(:to_s) # => "#<Object:0x00005614d7a24fa3>"

可以传入要调用的方法。在这种情况下,我们通过 :to_s。这在进行 Ruby 元编程时非常方便,因为这允许我们根据不同的需求调用不同的方法。

还可以使用 Send 来显示 Ruby 中的所有内容都是一个对象

1.send(:+, 1)  ## -> 2
3.send(:*, 2)  ## -> 6