Ruby中的send方法

45

我刚刚了解了 Ruby 中 send 的作用,但是看到这段代码还是感到困惑(它来自一个测试题,但无论如何已经过期了)。

x = [1,2,3]
x.send :[]=,0,2
x[0] + x.[](1) + x.send(:[],2)

我知道第一行将一个数组赋给了x, 但是我完全不理解:[] = ,0,2的作用,也不知道为什么需要使用send方法。 我不明白x.[](1)和x.send(:[], 2)在最后一行分别做了什么。

我真的很困惑,而且在网上找不到这方面的信息。

我已经找到了send方法的含义,但是对于整个代码仍然感到有些困惑。

5个回答

60
首先,像[](数组索引)和[]=这样的东西在Ruby中只是方法。 x是一个Array,而数组有一个[]=方法,它接受两个参数,一个索引和要设置的值。
使用send可以让你向对象传递任意的“消息”(方法调用),并传递任意的参数。
例如,你可以调用x.send :sort,将“sort”消息发送给数组。虽然sort不需要额外的参数,但我们也可以附加额外的参数传递给它。
另一方面,x#[]=接受两个参数。它的方法可以被认为是这样的:
def []=(index, value)
  self.set_value_at_index(index, value)
end

所以,我们可以使用send :[]=, 0, 2 来调用它,这就像调用 x[0] = 2 一样简洁,很棒吧?


好的,我仍然不理解逗号,为什么不是:[]= 0,2? - Xitcod13
10
因为:[]=也是send方法的一个参数,所以可以这样使用:send(:[]=, 0, 2) - Eureka

24

在Ruby中,a[0] = 2实际上是a.[]=(0, 2)的语法糖。

知道这一点后,你的第二行代码会使用元编程调用带有两个参数的[]=方法,正如你所猜测的那样。

对于你的第三行代码也是同样的原理:a[0]在Ruby中是x.[](0)的语法糖。

以下代码是等价于你的示例的简化版本:

x = [1, 2, 3]
x[0] = 2
x[0] + x[1] + x[2]

22

不用担心,在这些情况下Ruby可能有点棘手。让我们逐行检查代码:

x = [1,2,3]
x.send :[]=,0,2
x[0] + x.[](1) + x.send(:[],2)

第一行

第一行很清楚,它将一个由三个元素组成的数组分配给了x。就是这样。

第二行

第二行调用xObject#send方法,传递一个符号(记住,在Ruby中,以:开头的所有内容都是符号):[]=0(一个Fixnum)和2(另一个Fixnum)。
现在你只需要看一下send方法做了什么(就像你说过的那样):

调用由符号标识的方法,并传递任何指定的参数。

这意味着它将调用由:[] =标识的方法,并向其传递02。现在让我们看一下Array#[]=方法。此方法定义(如果需要,您可以进行重载)为:
class Array
    # ...
    def []=(a, b)
        # ...
    end
end

这个方法被send作为x.[]=(0, 2)调用,如果你问我,这很丑陋。这就是 Ruby 定义一种语法糖版本的原因:x[0] = 2,通常来说:
x.[]=(a, b)  -->  x[a] = b

在Array的情况下,我们还有以下内容:
x.[](a)  -->  x[a]

在这两种情况下,您可以自由选择在特定上下文中有意义的版本。

第三行

现在是第三行也是最后一行:

x[0] + x.[](1) + x.send(:[],2)

事情变得非常棘手。让我们分成以下几部分:

  1. x[0]
  2. x.[](1)
  3. x.send(:[], 2)

第一个很简单。它返回数组的第一个元素。

第二个是我们之前见过的语法糖,可以基本上转换为x[1],它返回数组的第二个元素。

第三个使用Object#send调用方法[]并将2传递给它。这意味着它调用x.[](2),也就是x[2]

结论

该代码

x = [1,2,3]
x.send :[]=,0,2
x[0] + x.[](1) + x.send(:[],2)

可以使用以下方式进行转换:

x.send(:[]=, a, b)  -->  x.[]=(a, b)
x.send(:[], a)  -->  x.[](a)
x.[]=(a, b)  -->  x[a] = b
x.[](a)  -->  x[a]

到:

x = [1,2,3]
x[0] = 2
x[0] + x[1] + x[2]

可以简化为:

2 + 2 + 3

这将导致:

7

@Jeffery 很好的解释..您可以解释一下 x[1]=2 的意思吗? - Catmandu
1
@PeeVee,数组x中索引为1的元素是第二个:2 - Shoe

7

send是Ruby中实现反射调用的一种方式。因此,这行代码的意思是:

x.send :[]=,0,2

相当于:
x[0] = 2

你可以这样理解:方法的名称是符号(在你的情况下是[] = ),然后你传入参数-0和2。

2

x[0]+x[1]+x[2]=2+2+3=7 我猜这就是答案。


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