为什么在*a =""之前调用p时,splat /一元运算符会更改指定值a?

Pat*_*und 7 ruby

给出一些关于我如何理解问题的背景.

在字符串上使用splat collect发送:to_a或:to_ary到String

class String
  def method_missing method, *args, &block
    p method #=> :to_ary
    p args   #=> []
    p block  #=> nil
  end
end

*b = "b"
Run Code Online (Sandbox Code Playgroud)

所以我认为重新定义:to_ary方法将是我所追求的.

class String
  def to_ary
    ["to_a"]
  end
end

p *a = "a" #=> "a"
p a        #=> "a"

*b = "b"
p b        #=> ["to_a"]
Run Code Online (Sandbox Code Playgroud)

现在这让我困惑不已.

打印*a ="a"的结果会更改分配给?的值?

进一步证明

class String
  def to_ary
    [self.upcase!]
  end
end

p *a = "a" #=> "a"
p a        #=> "a"

*b = "b"
p b        #=> ["B"]
Run Code Online (Sandbox Code Playgroud)

rob*_*rit 9

非常有趣的问题!Ruby接受这个表达式:

 p *a = "a"
Run Code Online (Sandbox Code Playgroud)

并将其翻译为以下内容:

 temp = (a = "a")
 p *temp
Run Code Online (Sandbox Code Playgroud)

所以发生的第一件事是a分配到"a",然后分配表达式的结果"a"被splatted并发送到p.由于p发送多个参数时的默认行为只是迭代并打印每个参数,因此只能看到"a"显示.

简而言之,它遵循"分配然后splat"评估顺序.因此在字符串被splatted之前a被分配"a".

但是,当您没有函数调用时,它被解释为如下所示:

# *a = "a" gets interpreted as:
temp = "a"
a = *temp
Run Code Online (Sandbox Code Playgroud)

这遵循"splat then assign"评估顺序.因此在字符串被splatted 之后a被分配.

您可以通过以下方式查看函数收到的内容:

def foo *args
  puts args.inspect
end

foo *a = "a"    # outputs ["a"]
a               # outputs "a"
Run Code Online (Sandbox Code Playgroud)

希望这可以清除正在发生的事情!

简而言之(感谢Mark Reed):

p *a = "a"    # interpreted as: p(*(a = "a"))
*a = "a"      # interpreted as: a = *("a")
Run Code Online (Sandbox Code Playgroud)