Ruby 如何返回两个值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28725500/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does Ruby return two values?
提问by Pete
Whenever I swap values in an array, I make sure I stored one of the values in a reference variable. But I found that Ruby can return two values as well as automatically swap two values. For example,
每当我交换数组中的值时,我都会确保将其中一个值存储在引用变量中。但我发现 Ruby 可以返回两个值以及自动交换两个值。例如,
array = [1, 3, 5 , 6 ,7]
array[0], array[1] = array[1] , array[0] #=> [3, 1]
I was wondering how Ruby does this.
我想知道 Ruby 是如何做到这一点的。
回答by tadman
Unlike other languages, the return value of any method call in Ruby is alwaysan object. This is possible because, like everything in Ruby, nilitself is an object.
与其他语言不同,Ruby 中任何方法调用的返回值始终是一个对象。这是可能的,因为就像 Ruby 中的所有东西一样,nil它本身就是一个对象。
There's three basic patterns you'll see. Returning no particular value:
您会看到三种基本模式。不返回特定值:
def nothing
end
nothing
# => nil
Returning a singular value:
返回奇异值:
def single
1
end
x = single
# => 1
This is in line with what you'd expect from other programming languages.
这符合您对其他编程语言的期望。
Things get a bit different when dealing with multiple return values. These need to be specified explicitly:
处理多个返回值时,情况会有所不同。这些需要明确指定:
def multiple
return 1, 2
end
x = multiple
# => [ 1, 2 ]
x
# => [ 1, 2 ]
When making a call that returns multiple values, you can break them out into independent variables:
在进行返回多个值的调用时,您可以将它们分解为独立变量:
x, y = multiple
# => [ 1, 2 ]
x
# => 1
y
# => 2
This strategy also works for the sorts of substitution you're talking about:
此策略也适用于您正在谈论的替代类型:
a, b = 1, 2
# => [1, 2]
a, b = b, a
# => [2, 1]
a
# => 2
b
# => 1
回答by J?rg W Mittag
No, Ruby doesn't actually support returning two objects. (BTW: you return objects, not variables. More precisely, you return pointers to objects.)
不,Ruby 实际上不支持返回两个对象。(顺便说一句:您返回的是对象,而不是变量。更准确地说,您返回的是指向对象的指针。)
It does, however, support parallel assignment. If you have more than one object on the right-hand side of an assignment, the objects are collected into an Array:
但是,它确实支持并行分配。如果您在赋值的右侧有多个对象,则这些对象将被收集到一个Array:
foo = 1, 2, 3
# is the same as
foo = [1, 2, 3]
If you have more than one "target" (variable or setter method) on the left-hand side of an assignment, the variables get bound to elements of an Arrayon the right-hand side:
如果在赋值的左侧有多个“目标”(变量或 setter 方法),则变量将绑定到Array右侧的元素:
a, b, c = ary
# is the same as
a = ary[0]
b = ary[1]
c = ary[2]
If the right-hand side is notan Array, it will be converted to one using the to_arymethod
如果右侧是不一个Array,它将使用被转换为一个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]
And if we put the two together, we get that
如果我们把两者放在一起,我们就会明白
a, b, c = d, e, f
# is the same as
ary = [d, e, f]
a = ary[0]
b = ary[1]
c = ary[2]
Related to this is the splat operator on the left-hand side of an assignment. It means "take allthe left-over elements of the Arrayon the right-hand side":
与此相关的是赋值左侧的 splat 运算符。它的意思是“取出右侧的所有剩余元素Array”:
a, b, *c = ary
# is the same as
a = ary[0]
b = ary[1]
c = ary.drop(2) # i.e. the rest of the Array
And last but not least, parallel assignments can be nested using parentheses:
最后但并非最不重要的是,并行赋值可以使用括号嵌套:
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]
When you returnfrom a method or nextor breakfrom a block, Ruby will treat this kind-of like the right-hand side of an assignment, so
当你return从一个方法或next或break一个块中时,Ruby 会将这种类型视为赋值的右侧,所以
return 1, 2
next 1, 2
break 1, 2
# is the same as
return [1, 2]
next [1, 2]
break [1, 2]
By the way, this also works in parameter lists of methods and blocks (with methods being more strict and blocks less strict):
顺便说一句,这也适用于方法和块的参数列表(方法更严格,块更不严格):
def foo(a, (b, c), d) p a, b, c, d end
bar {|a, (b, c), d| p a, b, c, d }
Blocks being "less strict" is for example what makes Hash#eachwork. It actually yields a singletwo-element Arrayof key and value to the block, but we usually write
例如,块“不那么严格”就是Hash#each工作的原因。它实际上yield是一个单独Array的 key 和 value两个元素到块,但我们通常写
some_hash.each {|k, v| }
instead of
代替
some_hash.each {|(k, v)| }
回答by sawa
tadman and J?rg W Mittag know Ruby better than me, and their answers are not wrong, but I don't think they are answering what OP wanted to know. I think that the question was not clear though. In my understanding, what OP wanted to ask has nothing to do with returning multiple values.
tadman 和 J?rg W Mittag 比我更了解 Ruby,他们的回答并没有错,但我认为他们没有回答 OP 想知道的问题。我认为这个问题并不清楚。在我的理解中,OP 想问的与返回多个值无关。
The real question is, when you want to switch the values of two variables aand b(or two positions in an array as in the original question), why is it not necessary to use a temporal variable templike:
真正的问题是,当您想切换两个变量a和b(或原始问题中数组中的两个位置)的值时,为什么没有必要使用temp像这样的时间变量:
a, b = :foo, :bar
temp = a
a = b
b = temp
but can be done directly like:
但可以直接完成,如:
a, b = :foo, :bar
a, b = b, a
The answer is that in multiple assignment, the whole right hand side is evaluated prior to assignment of the whole left hand side, and it is not done one by one. So a, b = b, ais not equivalent to a = b; b = a.
答案是,在多重赋值中,整个右手边先于整个左手边赋值,而不是一一完成。所以a, b = b, a不等价于a = b; b = a.
First evaluating the whole right hand side before assignment is a necessity that follows from adjustment when the both sides of =have different numbers of terms, and J?rg W Mittag's description may be indirectly related to that, but that is not the main issue.
在赋值之前首先评估整个右手边是当 的两边=都有不同的项数时进行调整的必要条件,而 J?rg W Mittag 的描述可能与此间接相关,但这不是主要问题。
回答by pronoob
Arrays are a good option if you have only a few values. If you want multiple return values without having to know (and be confused by) the order of results, an alternative would be to return a Hash that contains whatever named values you want.
如果您只有几个值,数组是一个不错的选择。如果您想要多个返回值而不必知道(并且被混淆)结果的顺序,另一种方法是返回一个包含您想要的任何命名值的哈希。
e.g.
例如
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

