Ruby 中避免误用赋值“=”的最佳实践是什么?

发布于 2024-10-27 19:15:06 字数 514 浏览 5 评论 0原文

我已经被咬了好几次了,因为我忘记了 Ruby 中的 x = y 使 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 的使用是否会成为我的第二天性,所以欢迎任何有用的提示。

I've been bitten a couple of times by forgetting that x = y in Ruby makes x refer to the same object as y; I'm too used to languages where it means, in Ruby terms, x = y.dup. Forgetting this, I inadvertently change y when I think it's safe on the right side of the assignment.

I can see that it would make sense to avoid simple x = y assignments without a special reason, but the same thing can be lurking in other places such as

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

where a later name << title would actually be changing person.last_name and not just name.

If this has happened to you, too, how have you learned to avoid it? Are there certain red flags or patterns to look for? Do you look with suspicion at each assignment you make? Do you use .dup a lot? I don't know if Ruby's usage will ever become second nature to me, so any useful tips would be welcome.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

爱本泡沫多脆弱 2024-11-03 19:15:06

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

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

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

complete_name = name + title

This may sound unorthodox in a (essentially imperative) language like Ruby, but my advice is: avoid collateral damages by not updating objects at all (except when strictly necessary); create new ones instead. You pay a bit of performance but you'll get code which is clearer, more compact, more modular and easier to debug.

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

So, in your example, just create a new string with a new name:

complete_name = name + title
分分钟 2024-11-03 19:15:06

只是对 tokland 答案的补充:

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

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

  1. 了解 Ruby 中的赋值是什么:只不过是命名一个对象。因此,当您说 y=x 时,您只是在说“我们为名为 x 的事物赋予另一个名称 y”。
  2. 姓名<< title 变异名为name的对象。
  3. name += title 获取名为 nametitle 的对象,将它们连接到另一个对象中,并分配该新对象名称名称。它不会改变任何东西。

Just an addition to tokland's answer:

Functional approach insists on immutability - i.e. not altering existing objects, but creating another whenever you want to change the original one. This is somewhat against the object-orientated paradigm that Ruby also brings (objects keep their state internally, which can be altered by calling methods on it), so you have to balance a bit between the two approaches (on the other hand, we benefit by having multiple paradigms easily accessible in a single language).

So, three things to remember for now:

  1. Learn what assignment in Ruby is: nothing but naming an object. So, when you say y=x, you are only saying "we give another name y to whatever was named x".
  2. name << title mutates object called name.
  3. name += title takes objects named name and title, concatenates them into another object, and assigns that new object name name. It doesn't mutate anything.
池予 2024-11-03 19:15:06

我也遇到过这样的情况,导致了bug,搞了半天才搞清楚。我基本上做了这样的事情

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

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

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

I also came across such a situation and it resulted in a bug, which I took half a day to figure out. I essentially did something like this

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

This code was inside a loop and in the loop, I expected the variable file_name to be again set to original value. But the object.file_name was changed, as I was performing file_name.gsub!. There are 2 ways to solve this. Either replace the .gsub! call with file_name = file_name.gsub or do file_name = object.file_name.dup. I opted for the second option.

I think we should be careful with methods having ! and <<, as they change the original object on which they are acting, especially after assignments like this.

妥活 2024-11-03 19:15:06

方法不应修改变量(例如通过使用移位运算符),除非其定义表明它将修改它。

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

A method should not modify a variable (e.g. by using the shift operator) unless its definition says it will modify it.

So: never modify an object in a method that didn't either (a) create it or (b) document that it modifies it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文