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

时间:2012-06-05 16:01:06

标签: ruby

提供一些关于我如何理解问题的背景信息。

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

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

*b = "b"

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

class String
  def to_ary
    ["to_a"]
  end
end

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

*b = "b"
p b        #=> ["to_a"]

现在这让我感到困惑。

打印* a =“a”的结果会更改分配给?

的值

进一步证明

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

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

*b = "b"
p b        #=> ["B"]

1 个答案:

答案 0 :(得分:9)

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

 p *a = "a"

并将其翻译成以下内容:

 temp = (a = "a")
 p *temp

所以首先发生的事情是a被分配到"a",然后分配表达式"a"结果会被摧毁,已发送至p。由于p发送多个参数时的默认行为只是迭代并打印每个参数,因此您只会看到"a"出现。

简而言之,它遵循“分配然后splat”评估顺序。因此,在字符串被喷溅之前,a会被分配到"a"

但是,如果没有函数调用,则会将其解释为:

# *a = "a" gets interpreted as:
temp = "a"
a = *temp

这是在“splat then assign”评估顺序之后。因此,在字符串被splatted后,a被分配

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

def foo *args
  puts args.inspect
end

foo *a = "a"    # outputs ["a"]
a               # outputs "a"

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

简而言之(感谢Mark Reed):

p *a = "a"    # interpreted as: p(*(a = "a"))
*a = "a"      # interpreted as: a = *("a")