为什么不能在Ruby代码块中重新分配变量?

逆向工程

为什么不调用这两个.map方法会带来相同的结果?第一个按预期方式工作,而第二个则无效。

array = ["batman","boobytrap"]

puts array.map { |x| x.reverse! }
=> namtab
=> partyboob

puts array.map { |x| x = x.reverse }
=> batman
=> boobytrap
约格午间

您的方法存在几个问题。

第一个问题是您没有正确隔离测试用例:在第一个测试用例中,您反转了数组中的字符串。在第二个测试用例中,您再次将它们反转如果您两次扭转某些东西会怎样?是的:什么都没有因此,您认为它不起作用的原因实际上正是它起作用的事实如果它工作(即不可逆的字符串),然后将打印之前反转字符串,你会觉得它的工作。

因此,第1课:请始终隔离测试用例!

问题2是第二段代码没有执行(可能)您认为的那样。x是局部变量(因为它以小写字母开头)。局部变量对于定义它们的作用域是局部的,在这种情况下为块。因此,x仅存在于块内部。您分配了它,但是分配后从未对其执行任何操作。因此,分配实际上是不相关的。

什么相关的,是块的返回值。现在,在Ruby中,赋值计算的是赋值,因此考虑到to的赋值x是多余的,我们可以删除它,而您的代码实际上与此完全等效:

array.map { |x| x.reverse }

您的第三个问题是,第一部分也没有做您(可能)认为做的事情。Array#map返回一个数组,并保持原始数组不变,但会改变字符串!换句话说:它的主要操作模式是副作用除了副作用,它返回字符串相反,它是让你感到困惑的另一件事。它也可能返回而表明它具有副作用,在这种情况下,您可能会看到以下内容:String#reverse! nil

array = %w[batman boobytrap]

array.map(&:reverse!)
#=> [nil, nil]

array
#=> ['namtab', 'partyboob']

正如你可以看到,如果 String#reverse! 没有回报nil,你会看到如下:

  • array.map返回一个数组,其元素是该块的返回值,这仅仅是nil
  • array现在仍包含与String以前相同的对象,但是它们已被突变

现在,由于String#reverse!实际上确实返回了相反的结果String,所以您实际观察到的是:

array = %w[batman boobytrap]

array.map(&:reverse!)
#=> ['namtab', 'partyboob']

array
#=> ['namtab', 'partyboob']

array.map(&:reverse)
#=> ['batman', 'boobytrap']

array
#=> ['namtab', 'partyboob']

这使我进入第二课:副作用和共同的可变状态是邪恶的!

您应该同时避免副作用和共享的可变状态(理想情况下通常是可变状态,但是在不同部分之间共享的可变状态尤其有害)。

他们为什么邪恶?好吧,即使在这个极其简单的小例子中,只要看看他们有多困惑?您能想象在更大得多的应用程序中发生同样的事情吗?

副作用的问题在于它们“在侧面发生”。它们不是参数,也不是返回值。您不能打印出来,检查它们,将它们存储在变量中,在单元测试中将它们置为断言,等等。

共享的可变状态(顺便说一下,突变只是一种副作用)的问题在于,它可以实现“远距离的怪异动作”:您在代码的一个位置有一块数据,但是这块数据与您的代码的其他位置共享。现在,如果一个地方对数据进行了突变,那么另一个地方似乎将神奇地将其数据更改为隐藏在其下。在这里的示例中,共享状态是数组内的字符串,并且在一行代码中对它们进行突变会使它们在另一行代码中也发生更改。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么不能在Rails控制器中重新分配类变量

为什么不能在Swift中重新分配实例方法?

为什么传递给函数的对象可以被突变但不能在javascript中重新分配?

在with块中重新分配变量

为什么不能在实例块中为最终的静态变量分配值?

为什么不能在init块编译中初始化变量接口属性的代码?

为什么不能在try / catch块中访问变量?

JavaScript中的奇怪示例,为什么我不能通过函数的参数重新分配全局变量的值?

为什么不能将空代码块分配给Javascript中的变量?

为什么在重新分配之前在新块中使用 let 变量会出错?

为什么我不能在代码中删除中间变量?

为什么不能重新分配window.document属性?

为什么我们不能在INTERFACE的静态块内分配变量?OCA

局部变量的内存被重新分配 - 为什么

为什么重新分配字符串不会减少Ruby中的内存使用量?

为什么'error'变量重新分配在功能上不属于catch {}块的范围?

当 ArrayList 重新分配时,为什么 Java 中的变量不会失效?

为什么在 JavaScript 中没有重新分配循环内的“常量”变量?

为什么不能在动态分配的内存块中存储极大的单个值?

为什么我们可以通过在C代码中重新分配变量来永久避免寄存器溢出?

为什么我可以重新分配dict.update但不能重新分配dict .__ setitem__

VS Code中的JavaScript:为什么不能在“ switch”语句中折叠“ case”代码块?

C ++变量重新分配被代码忽略

為什麼不能在solidity中重新分配合約級別的值?

为什么不能在函数文字中为变量分配占位符?

为什么不能在Ruby的单例类定义中访问类实例变量?

为什么不能重新分配函数表达式的名称?

为什么不能重新分配已完全初始化的数组?

在if / else中重新分配变量(JavaScript)