3

x = y我忘记了在 Ruby 中让 x 引用与 y 相同的对象,我已经被咬过几次了。我太习惯于用 Ruby 术语表示x = y.dup. 忘记这一点,y当我认为在作业的右侧是安全的时,我不经意间改变了。

我可以看到在没有特殊原因的情况下避免简单的分配是有意义x = y的,但同样的事情可能潜伏在其他地方,例如

name = (person.last_name.blank? ? 'unknown' : person.last_name)

稍后name << title实际上会更改 person.last_name 而不仅仅是名称。

如果这也发生在你身上,你是如何学会避免它的?是否有某些危险信号或模式需要寻找?你对你所做的每一项任务都持怀疑态度吗?你用.dup的很多吗?我不知道 Ruby 的使用是否会成为我的第二天性,所以欢迎任何有用的提示。

4

4 回答 4

5

这在像 Ruby 这样的(本质上是命令式的)语言中可能听起来不正统,但我的建议是:通过不更新对象来避免附带损害(除非绝对必要);而是创建新的。你付出了一点性能,但你会得到更清晰、更紧凑、更模块化和更容易调试的代码。

http://en.wikipedia.org/wiki/Functional_programming

因此,在您的示例中,只需创建一个具有新名称的新字符串:

complete_name = name + title
于 2011-03-26T15:32:37.027 回答
1

只是对 tokland 答案的补充:

函数式方法坚持不变性——即不更改现有对象,而是在您想要更改原始对象时创建另一个对象。这在某种程度上违背了 Ruby 也带来的面向对象范式(对象在内部保持其状态,可以通过调用其上的方法来更改),因此您必须在两种方法之间进行一些平衡(另一方面,我们受益通过使用单一语言轻松访问多个范例)。

所以,现在要记住三件事:

  1. 了解 Ruby 中的赋值是什么:只是命名一个对象。因此,当您说 时y=x,您只是在说“我们给y任何被命名的东西取另一个名字x”。
  2. name << title 对名为 的对象进行变异name
  3. name += title获取名为nameand的对象,将title它们连接到另一个对象中,并分配该新对象 name name。它不会改变任何东西。
于 2011-03-26T19:12:46.150 回答
0

我也遇到过这样的情况,导致了一个bug,我花了半天时间才弄明白。我基本上做了这样的事情

hash = {....}
filename = object.file_name
hash.each |k, v| {file_name.gsub!(k, v) if file_name.include? k}

这段代码在循环中,在循环中,我希望变量file_name再次设置为原始值。但是 object.file_name 已更改,因为我正在执行file_name.gsub!. 有两种方法可以解决这个问题。.gsub!将call替换为file_name = file_name.gsub或 do file_name = object.file_name.dup。我选择了第二个选项。

我认为我们应该小心具有!and的方法<<,因为它们会改变它们所作用的原始对象,尤其是在这样的赋值之后。

于 2011-03-26T17:15:31.653 回答
0

一个方法不应该修改一个变量(例如通过使用移位运算符),除非它的定义说它会修改它。

所以:永远不要在没有(a)创建它或(b)记录它修改它的方法中修改对象。

于 2011-03-26T18:30:32.783 回答