配列の値を交換するときはいつでも、参照変数に値の1つを保存したことを確認します。しかし、Rubyは2つの値を返すだけでなく、2つの値を自動的に交換できることがわかりました。例えば、
array = [1, 3, 5 , 6 ,7]
array[0], array[1] = array[1] , array[0] #=> [3, 1]
Rubyがこれをどのように行うのか疑問に思いました。
回答:
他の言語とは異なり、Rubyのメソッド呼び出しの戻り値は常にオブジェクトです。これは、Rubyのすべてと同様に、nil
それ自体がオブジェクトであるために可能です。
あなたが見る3つの基本的なパターンがあります。特定の値を返さない:
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 ]
複数の値を返す呼び出しを行う場合、それらを独立した変数に分割できます。
x, y = multiple
# => [ 1, 2 ]
x
# => 1
y
# => 2
この戦略は、あなたが話している種類の置換にも有効です:
a, b = 1, 2
# => [1, 2]
a, b = b, a
# => [2, 1]
a
# => 2
b
# => 1
[1, 2]
を返すことができ、これは上記の例と同じように機能します。
1,2
それ自体は無効ですが、return 1,2
またはのどちらかが無効であることを明確にすべき[1,2]
でした。
いいえ、Rubyは実際には2つのオブジェクトを返すことをサポートしていません。(ところで、変数ではなくオブジェクトを返します。より正確には、オブジェクトへのポインタを返します。)
ただし、並列割り当てはサポートされています。割り当ての右側に複数のオブジェクトがある場合、オブジェクトは次のように収集されますArray
。
foo = 1, 2, 3
# is the same as
foo = [1, 2, 3]
割り当ての左側に複数の「ターゲット」(変数またはセッターメソッド)がある場合、変数Array
は右側のの要素にバインドされます。
a, b, c = ary
# is the same as
a = ary[0]
b = ary[1]
c = ary[2]
右側である場合はない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]
そして、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) # i.e. 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]
あなたの場合は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]
ちなみに、これはメソッドとブロックのパラメーターリストでも機能します(メソッドはより厳密で、ブロックはそれほど厳密ではありません)。
def foo(a, (b, c), d) p a, b, c, d end
bar {|a, (b, c), d| p a, b, c, d }
「それほど厳密でない」ブロックは、たとえば、機能するものHash#each
です。また、実際yield
のsa シングル 2要素Array
ブロックへのキーと値のが、我々は通常、書き込み
some_hash.each {|k, v| }
の代わりに
some_hash.each {|(k, v)| }
tadmanとJörgW Mittagは私よりもRubyをよく知っていて、答えは間違っていませんが、OPが知りたかったことに答えているとは思いません。質問ははっきりしていなかったと思います。私の理解では、OPが求めたかったことは、複数の値を返すこととは関係ありません。
次の2つの変数の値を切り替えたいとき本当の問題は、あるa
とb
、なぜ一時的な変数を使用する必要はありません(元の質問のように、配列または2つの位置を)temp
のように:
a, b = :foo, :bar
temp = a
a = b
b = temp
しかし、次のように直接行うことができます:
a, b = :foo, :bar
a, b = b, a
その答えは、多重代入では、右側全体が左側全体の代入の前に評価され、それが1つずつ実行されるわけではないということです。したがって、a, b = b, a
と同等ではありませんa = b; b = a
。
代入の前に最初に右辺全体を評価することは、両側=
の項の数が異なる場合の調整に続く必要性であり、JörgW Mittagの説明はそれに間接的に関連している可能性がありますが、それは主要な問題ではありません。