Reputation: 532
I'm not sure what exactly is going on with the code snippet below.
>> a, b = ["ho", "hey"]
=> ["ho", "hey"]
>> a
=> "ho"
>> b
=> "hey"
>> c, d = "foo", "bar"
=> ["foo", "bar"]
>> c
=> "foo"
>> d
=> "bar"
>> a, b = ["blerg"], ["baz"]
=> [["blerg"], ["baz"]]
>> a
=> ["blerg"]
>> b
=> ["baz"]
Why wouldn't line 1 return a => ["ho"]
?
So behind the scenes, what's the difference between these three assignments (a, b = ["ho", "hey"]
, c, d = "foo", "bar"
, a, b = ["blerg"], ["baz"]
)?
Upvotes: 7
Views: 7473
Reputation: 2819
a, b = ["ho", "hey"]
a
is assigned the first element of the array, which is the string "ho". Nothing weird.
a, b = ["blerg"], ["baz"]
a, b = [["blerg"], ["baz"]]
These two are the same, as you can see by their return values. So a is assigned the first element, which is an array with one element: ["blerg"]
.
Similarly,
c, d = "foo", "bar"
Is the same as
c, d = ["foo", "bar"]
Upvotes: 11
Reputation: 18567
In Ruby, =
takes a list of variables on the left, and a list of expressions on the right. It assigns the the first variable to the value of the first expression, the second variable the value of the second expression, and so on. If there are more variables than expressions, the leftover variables get assigned the value nil
.
> a, b, c, d = "foo", 2+3, Array.new(2, 3), [:c, :d]
> a # => "foo"
> b # => 5
> c # => [3, 3]
> d # => [:c, :d]
> e # => nil
There are two exceptions:
Left side has only one variable, right side has multiple expressions
In this case, the above rule would say that the variable just gets set to the value of the first expression on the right. Instead, the variable gets set to the Array consisting of the values of the expression on the right. In the example below, we see a
gets the value [:b, :c]
, instead of just :b
:
> a = :b, :c
> a # => [:b, :c]
This is equivalent to:
> *a = :b , :c
> a # => [:b, :c]
The other exception:
The left side has multiple variables, the right side has only one expression and it's an Array
Again, the original rule would imply that the first variable gets set to that whole Array, and the rest of the variables would be nil. However, that Array effectively ends up getting replaced with the list of its elements, and then =
reverts to the "default" behaviour described in the beginning:
> a, b, c = [:d, [:e, :f]]
> a # => :d
> b # => [:e, :f]
> c # => nil
This is equivalent to a, b, c = *[:d, [:e, :f]]
, or just a, b, c = :d, [:e, :f]
Upvotes: 7
Reputation: 11001
The assignment operator in the Ruby Language allow Multiple assignments (aka: parallel assignment).
Say lvalue the left side variables or attributes on the left side of the assignment operator (=) and say rvalue the right side values.
By Multiple assignments you can assign one comma delimited list to another, with corresponding variables on the left side getting corresponding values from the right
a, b = ["ho", "hey"]
if the last rvalue is an array, you can prefix it with an asterisk, which effectively expands it into its constituent values in place. the asterisk is not necessary if the rvalue is the only thing on the right-hand side the array will be expanded automatically.
To better understand, try this:
>> a,b,c = "1",*["ho", "hey"]
=> ["1", "ho", "hey"]
>> a
=> "1"
>> b
=> "ho"
>> c
=> "hey"
let's see again:
>> a,b,c = "1",["ho", "hey"]
=> ["1", ["ho", "hey"]]
>> a
=> "1"
>> b
=> ["ho", "hey"]
>> c
=> nil
as you can see, if we don't prefix the array with the * then the array is not expanded.
c, d = "foo", "bar"
"foo", "bar" are two literal Strings assigned to the corresponding variable on the left side.
a, b = ["blerg"], ["baz"])?
["blerg"]
and ["baz"]
are two Array each one containing one element of class String;
therefore each "Array of a sigle String" is assigned to the corresponding variable on the left side.
Upvotes: 0
Reputation: 28554
In the examples you point out, there are 2 different structures being used on the right hand side of the multiple assignment:
Multiple assignment from a simple array
array = ["item1", "item2"]
a, b = array
# a => "item1"
# b => "item2"
Multiple assignment from an array who's elements are themselves single element arrays (aka: a multi-dimensional array)
array = [["item1"], ["item2"]]
a, b = array
# a => ["item1"]
# b => ["item2"]
Multiple assignment unwraps only the first level of a multi-dimensional array and allows you to assign those elements to multiple variables on the left hand side of the expression. So when you do this with a multi-dimensional array, it takes the first element wich is ["item1"]
and assigns in to a
, then moves on to the next element, which is ["item2"]
and assigns it to b
. The multiple assignment doesn't "dig deeper" into the multi-dimensional array, it performs the assignment from the first level of elements.
Upvotes: 0