Why doesn't a Ruby spline work to force an array on conditional assignment?

Although the splat ( * ) construct is usually called the splat operator, it is clear that it is a different beast compared to other unary operators, such as the negation operator ( ! ).

When used in assignment ( = ), splat works fine on its own (that is, it is not enclosed in brackets), but it creates an error when used with conditional assignment ( ||= ). Example:

 a = *(1..3) #=> [1, 2, 3] b ||= *(1..3) SyntaxError: (irb):65: syntax error, unexpected * 

I'm not looking for alternative ways to do the same thing, but I'm looking for someone who better understands Ruby internals to explain why this use of the splat construct works in the first case, but not the second.

+6
source share
2 answers

Here is my understanding of the practical purpose of splat. This is for Ruby 2.2 MRI / KRI / YARV.

Ruby splat destroys an object in an array at the time of assignment.

All these examples give the same result when a false:

 a = *(1..3) a = * (1..3) a =* (1..3) a = *1..3 a = * 1..3 a = * a || (1..3) a = * [1, 2, 3] => [1, 2, 3] 

Split performs destructuring during installation, as if you wrote this:

 a = [1, 2, 3] 

(Note: calling splat calls #to_a . This means that there are no changes when marking up the array. It also means that you can define your own types of destructuring for any of your class if you want.)

But these statements are not fulfilled:

 *(1..3) * 1..3 * [1,2,3] false || *(1..3) x = x ? x : *(1..3) => SyntaxError 

These statements fail because there is no assignment that occurs exactly when the symbol occurs.

Your question in this case:

 b ||= *(1..3) 

Ruby extends it to:

 b = b || *(1..3) 

This instruction fails because there is no assignment that occurs exactly when the character occurs.

If you need to solve this in your own code, you can use temp var, for example:

 b ||= (x=*(1..3)) 

Worth mentioning: here is a completely different use of splat when it is on the left side of the expression. This mark is a low-priority greedy compilation during a parallel assignment.

Examples:

 *a, b = [1, 2, 3] #=> a is [1, 2], b is 3 a, *b = [1, 2, 3] #=> a is 1, b is [2, 3] 

So this is a parsing:

 *a = (1..3) #=> a is (1..3) 

It sets a for all results on the right side, i.e. range.

In the rare case when a sign can be understood as a destructor or collector, then the destructor has a predisposition.

This line:

 x = * y = (1..3) 

Evaluates the following:

 x = *(y = (1..3)) 

Not this:

 x = (*y = (1..3)) 
+7
source

By splatting *(1..3) in your expression, you get 1, 2, 3 , and when it is assigned, it behaves like a mass assignment, but the ruby ​​does not seem to support it for conditional assignment. That is, a=1,2,3 is just the syntactic sugar of a ruby. Just use the array explicitly:

 a ||= [*1..3] #=> [1, 2, 3] 

And in fact, you only use part of the splat functions here: autoconversion for the array :) so you can just do:

 a ||= (1..3).to_a #=> [1, 2, 3] 
0
source

Source: https://habr.com/ru/post/985939/


All Articles