是否';厄普卡斯';不在Ruby中变异变量?

是否';厄普卡斯';不在Ruby中变异变量?,ruby,Ruby,我只是想确定我明白这里发生了什么。我知道+=是重新分配的,所以也许这就是str没有被修改的原因,但是为什么upcase在这里修改str def change_me(str) str+=“?” 上回! 结束 问:“你叫什么名字?” 改变我(问题) 提出问题 “你叫什么名字?” =>零 执行str+=“?”时,您正在创建一个新字符串,因此str指向的字符串与作为参数传递的字符串不同 你所做的基本上是这样的: def change_me(str) new_str = str + "?&q

我只是想确定我明白这里发生了什么。我知道+=是重新分配的,所以也许这就是str没有被修改的原因,但是为什么
upcase在这里修改str

def change_me(str)
str+=“?”
上回!
结束
问:“你叫什么名字?”
改变我(问题)
提出问题
“你叫什么名字?”
=>零

执行
str+=“?”
时,您正在创建一个新字符串,因此
str
指向的字符串与作为参数传递的字符串不同

你所做的基本上是这样的:

def change_me(str)
  new_str = str + "?"
  new_str.upcase!
end
这就是为什么没有更改以前的字符串。如果希望该功能产生副作用,应执行以下操作:

def change_me(str)
  str << "?"
  str.upcase!
end
def change_me(str)
str
“上格!”不在Ruby中变异变量

方法不可能对变量进行变异。Ruby是一种面向对象的语言,因此方法可以改变对象(更准确地说,方法可以改变它的接收者),但变量不是Ruby中的对象。(与大多数其他语言一样,几乎没有以变量为对象的语言。)

变异变量的唯一方法是赋值。请注意,我们通常不讨论“变异”变量,而是讨论“重新绑定”或“重新分配”

我只是想确定我明白这里发生了什么。我知道+=是重新分配的,所以也许这就是str没有被修改的原因,但是为什么
upcase在这里修改str

同样,您混淆了变量和对象<代码>上传
修改由
str
引用的对象,但不修改
str

听起来你希望Ruby是一种通过引用传递的语言,但事实并非如此。Ruby完全是按值传递的,始终没有例外。更准确地说,传递的值是指向对象的不可修改、不可伪造的指针

以下是执行流程中发生的情况:

question=“你叫什么名字”
  • 字符串文本
    “What's your name”
    将被计算,结果是一个
    字符串
    对象,其内容为
    What's your name
  • 局部变量
    question
    用一个不可变、不可伪造的指针初始化,该指针指向在步骤#1中创建的字符串对象
change\u me(问题)
  • 局部变量
    question
    被取消引用,导致指向步骤#1中创建的字符串对象的不可变、不可伪造的指针
  • 将制作该指针的副本
  • 步骤4的副本被放入调用
    change\u me
str+=“?”
  • change\u me
    方法主体内部,参数绑定
    str
    绑定到从步骤4和步骤5复制的不可变不可伪造指针
  • 这一行被分解为
    str=str+“?”
    ,因此发生的是:
    • str
      被取消引用,导致从步骤4、5和6复制的不可变、不可伪造指针
    • 我们跟随指针并将消息
      +
      发送到对象,该对象带有一个不可变的、不可伪造的指针,指向通过将字符串文本
      “?”
      作为参数求值而创建的字符串对象
    • String#+
      返回一个新字符串(或者更准确地说,是指向新字符串的不可变、不可伪造的指针)
    • str
      被重新绑定到调用
      str+(“?”
      返回的新的不可变、不可伪造指针
str.upcase
  • str
    被取消引用,导致从步骤7c到7d的新的不可变、不可伪造指针
  • 我们跟随指针并发送消息
    upcase到对象
  • String#upcase
    将改变receiver对象(在本例中,是步骤#7c中新创建的字符串),使所有字母都大写
  • String#upcase对接收器做了任何更改,它将返回指向接收器对象本身的不可变、不可格式化指针(即用于调用方法的指针),或者如果字符串已经是大写或不包含任何字母,它将返回指向对象的不可变、不可格式化指针
    nil
回到
change\u me(问题)
  • 然而,这个返回值只是被忽略了,被丢弃了,没有打印,没有分配给变量,没有作为参数传递给其他方法,没有存储在数据结构中
提出问题
好的,现在变量被取消引用,我将保存细节,等等

关键部分是:变量
question
从未被触及,也从未被重新赋值,因此它仍然包含与整个过程完全相同的内容:指向步骤1和步骤2中字符串对象的不可变、不可伪造的指针

我们将此对象指定给变量,并且我们:

  • 从不重新指定变量,因此变量仍然指向同一对象
  • 从未要求对象自身发生变异,因此对象的内容仍然相同
因此,对象仍然不变,变量仍然指向同一个对象,因此我们得到的结果是没有任何变化

我们在
change\u me
方法内部更改了
str
参数绑定的绑定,但该绑定是该方法的本地绑定。(参数绑定实际上相当于局部变量。)因此,它在方法返回时就不存在了

我们更改了新创建的string对象,但由于我们从未获得指向该对象的指针,因此无法访问它。一个指针存储在
str
中,但它已经不存在了。另一个指针是从
change\u me
返回的,但是我们把它扔掉了,所以它也不见了。因为没有参考t
def change_me(str)
  str.upcase!
  42
end

x = 'hello'
puts x # => hello
change_me(x)
puts x # => HELLO
def change_me(str)
  p str.object_id
  str += "?"
  p str.object_id
  str.upcase!
  p str.object_id
end

def change_me_2(str)
  p str.object_id
  str << "?"
  p str.object_id
  str.upcase!
  p str.object_id
end
def change_me(str)
  str.upcase + '?'
end
question = "what's your name"
question = change_me(question)
question = change_me("what's your name")
def change_me(str)
  str += "?"
  str.upcase!
end

question = "whats your name"
puts change_me(question)