13

我刚刚向 Ruby splat oprator 介绍了自己。我玩了很多方法。但是下面的实验不知何故让我想了两次:)

langs = ["java", "csharp", "ruby", "haskell" ]
# => ["java", "csharp", "ruby", "haskell"]

 l1,*,l2 = *langs
# => ["java", "csharp", "ruby", "haskell"]
 l1
# => "java"
 l2
# => "haskell"

 l1,*,*,l2 = *langs
SyntaxError: (irb):27: syntax error, unexpected tSTAR
l1,*,*,l2 = *langs
      ^
    from /usr/bin/irb:12:in `<main>'

是的,错误很明显,因为我*(splat)在同一个参数列表中使用了超过 1 个运算符。

现在我试着玩它。

l1,(*),(*),l2 = *langs
# => ["java", "csharp", "ruby", "haskell"]

啊!在这里有效。但不明白为什么会这样?

 l1
# => "java"
 l2
# => "haskell"
 l1,(*),l2 = *langs
# => ["java", "csharp", "ruby", "haskell"]
 l1
# => "java"
 l2
# => "ruby"

从上面的示例中,它似乎正在跳过数组元素。

问题是:

  • (a) 运算符 (*) 叫什么?

  • (b) 当我在 splat(*) 中使用l1,*,l2 = *langs它时,它会消耗所有元素 - "csharp", "ruby"。有什么方法可以从*技术上查看那里的消耗量吗?显然,我正在使用 if l1,*,l2 = *langsnot by l1,l*,l2 = *langs

4

3 回答 3

9

这是由于括号如何与Matz 解释的并行分配一起工作。

例如:

a, b, c = *[1, 2, 3]
a => 1
b => 2
c => 3

不同于:

a, (b, c) = *[1, 2, 3]
a => 1
b => 2
c => nil

基本上,括号说:将此索引处的右侧元素分配给括号中的变量。所以 2 被分配给b,索引处没有任何东西1可以分配给c。同样, (*) 将只获取给定索引处的元素并分发它。

# the * is interpreted to mean 'take all remaining elements'
a, * = 1, 2, 3, 4

# the * is interpreted to mean 'take all remaining elements except
# the last element'
a, *, c = 1, 2, 3, 4

# incorrect syntax, can't splat more than once on all remaining
# elements
a, *, *, c = 1, 2, 3, 4

# the * is interpreted to mean 'take all elements at index 1'
a, (*), c = 1, 2, 3, 4

# the *'s are interpreted to mean 'take all elements at index 1,
# then again at index 2'
a, (*), (*), c = 1, 2, 3, 4

通常,*运算符与变量结合使用*foo- 但如果不是,它将保留其位置并像变量一样进行元素分配(基本上丢弃它们)

于 2013-02-18T20:28:22.143 回答
6

这样想:括号本身(忽略变量名或 splat 运算符)正在访问数组中的单个元素:

l1,  (), (), l2 = *['a', 'b', 'c', 'd']
 ^   ^   ^   ^
'a' 'b' 'c' 'd'

如果它是一个数组数组,那么使用括号会更有意义:

>> l1,(l3, l4),(l5, l6),l2 = *['a', ['b', 'c'], ['d', 'e'], 'f']
=> ["a", ["b", "c"], ["d", "e"], "f"]
>> l1
=> "a"
>> l3
=> "b"
>> l4
=> "c"
>> l5
=> "d"
>> l6
=> "e"
>> l2
=> "f"

因此 (*) 从数组中获取单个元素,并对其进行 splat 分配。括号本身采用 SINGLE 元素,然后 splat 采用该单个元素并“splats”它。

值得注意的是,当从数组执行多变量赋值时,数组端不需要 splat:

>> a,b,c = ['a', 'b', 'c']
=> ["a", "b", "c"]
>> a
=> "a"
>> b
=> "b"
>> c
=> "c"
于 2013-02-18T20:49:54.503 回答
6

(*)实际上只是从右侧读取一个元素。考虑这个例子,它在langs数组中有第五个元素:

langs = ["java", "csharp", "ruby", "haskell", "python" ]

因此,当您使用普通的 splat 时,您会得到:

l1,*,l2 = langs

l1 #=> "java"
l2 #=> "python"

与带括号的示例相反:

l1,(*),(*),l2 = langs

l1 #=> "java"
l2 #=> "haskell"

不过我想提一下,对于这种情况,您通常会使用_将中间值分配给“无”(相当于最后一个示例):

l1,_,_,l2 = langs

l1 #=> "java"
l2 #=> "haskell"

如果您想查看最终在中间值中的内容,可以将值显式分配给变量,如下所示:

l1,*m,l2 = *langs

l1 #=> "java"
l2 #=> "python"
m  #=> ["csharp","ruby","haskell"]

或与其他示例:

l1,(*m1),(*m2),l2 = langs

l1 #=> "java"
l2 #=> "haskell"
m1 #=> ["csharp"]
m2 #=> ["ruby"]

所以我希望这清楚地表明(*)它本身不是一个运算符,而实际上只是括号内的一个 splat,因此没有自己的名字。

于 2013-02-18T21:16:15.207 回答