Ruby如何返回两个值?

每当我交换一个数组中的值时,我确定我将其中一个值存储在一个引用variables中。 但是我发现Ruby可以返回两个值,也可以自动交换两个值。 例如,

array = [1, 3, 5 , 6 ,7] array[0], array[1] = array[1] , array[0] #=> [3, 1] 

我想知道Ruby是如何做到这一点的。

与其他语言不同,Ruby中任何方法调用的返回值都是一个对象。 这是可能的,因为像Ruby中的所有东西一样, nil本身就是一个对象。

有三种基本模式,你会看到。 没有特别的价值:

 def nothing end nothing # => nil 

返回一个奇异的值:

 def single 1 end x = single # => 1 

这符合您对其他编程语言的期望。

处理多个返回值时,情况会有所不同。 这些需要明确规定:

 def multiple return 1, 2 end x = multiple # => [ 1, 2 ] x # => [ 1, 2 ] 

在进行返回多个值的调用时,可以将它们分解为独立variables:

 x, y = multiple # => [ 1, 2 ] x # => 1 y # => 2 

这个策略也适用于你所说的replace种类:

 a, b = 1, 2 # => [1, 2] a, b = b, a # => [2, 1] a # => 2 b # => 1 

不,Ruby实际上不支持返回两个对象。 (顺便说一句:你返回对象,而不是variables,更准确地说,你返回指向对象的指针。)

但是,它支持并行分配。 如果在赋值的右侧有多个对象,则这些对象将被收集到一个Array

 foo = 1, 2, 3 # is the same as foo = [1, 2, 3] 

如果在赋值的左侧有多个“目标”(variables或设置方法),variables将被绑定到右侧Array元素:

 a, b, c = ary # is the same as a = ary[0] b = ary[1] c = ary[2] 

如果右侧不是 Array ,则使用to_ary方法将其转换为一个to_ary

 a, b, c = not_an_ary # is the same as ary = not_an_ary.to_ary a = ary[0] b = ary[1] c = ary[2] 

如果我们把这两个放在一起,我们可以得到

 a, b, c = d, e, f # is the same as ary = [d, e, f] a = ary[0] b = ary[1] c = ary[2] 

与此相关的是作业左侧的摔跤运算符。 这意味着“在右边拿走Array 所有剩余元素”:

 a, b, *c = ary # is the same as a = ary[0] b = ary[1] c = ary.drop(2) # ie the rest of the Array 

最后但并非最不重要的是,平行分配可以使用圆括号嵌套:

 a, (b, c), d = ary # is the same as a = ary[0] b, c = ary[1] d = ary[2] # which is the same as a = ary[0] b = ary[1][0] c = ary[1][1] d = ary[2] 

当你从一个方法或next一个方法return ,或者从一个块或一个块break到一个块时,Ruby会把这种types看作是一个赋值的右边,所以

 return 1, 2 next 1, 2 break 1, 2 yield 1, 2 # is the same as return [1, 2] next [1, 2] break [1, 2] yield [1, 2] 

顺便说一下,这也适用于方法和块的参数列表(方法更严格,块更不严格):

 def foo(a, (b, c), d) pa, b, c, d end bar {|a, (b, c), d| pa, b, c, d } 

例如,“不太严格”的块就是让Hash#each有效。 它实际上yield一个单一的两元素Array的键和值的块,但我们通常写

 some_hash.each {|k, v| } 

代替

 some_hash.each {|(k, v)| } 

tadman和JörgW Mittag比我更了解Ruby,他们的回答没有错,但我不认为他们正在回答OP想知道的事情。 我认为这个问题并不清楚。 在我的理解中,OP想要问什么与返回多个值无关。


真正的问题是,当你想切换两个variablesab的值(或者像原始问题那样在一个数组中有两个位置)时,为什么没有必要使用如下的时间variablestemp

 a, b = :foo, :bar temp = a a = b b = temp 

但可以直接完成:

 a, b = :foo, :bar a, b = b, a 

答案是,在多次赋值中,整个右手边的整个左手边的赋值之前被评估,而不是一个接一个地完成。 所以a, b = b, a不等于a = b; b = a a = b; b = a

在分配之前首先评估整个右手边是调整之后的必然结果,当两边有不同数量的术语时,JörgW Mittag的描述可能与此有间接关系,但这不是主要问题。

如果你只有几个值,数组是一个很好的select。 如果你想得到多个返回值,而不必知道结果的顺序(并且被它们混淆),另一种方法是返回一个包含你想要的任何名字值的Hash。

例如

 def make_hash x = 1 y = 2 {:x => x, :y => y} end hash = make_hash # => {:x=>1, :y=>2} hash[:x] # => 1 hash[:y] # => 2