为什么不调用这两个.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] 删除。
我来说两句