谁能解释一个字符串为什么会意外突变。我的导师对此进行了投标,但是我真的不明白为什么。
答案 0 :(得分:3)
关于常量引用的对象如何变异的示例:
FOO = 'foo'
p FOO # => "foo"
FOO.upcase!
p FOO # => "FOO" (no errors)
BAR = 'bar'.freeze
p BAR # => "BAR"
BAR.upcase! # => freeze.rb:8:in `upcase!': can't modify frozen String (RuntimeError)
freeze
常量引用的对象可以防止代码的意外行为,因此开发人员可以对其进行修复或其他任何操作。
要查看freeze
仅冻结对象,请查看如果将新值分配给常量,则抛出的错误将有所不同:
BAZ = 'baz'.freeze # => warning: previous definition of BAZ was here
BAZ = 'bazbaz' # => warning: already initialized constant BAZ
答案 1 :(得分:1)
以下是一些使字符串变异的方法:<<
,gsub!
,downcase!
,replace
...
假设有一个网站“ Chitter”,用户在其中发布有关其日常生活的“ cheets”。让我们假设Chitter帐户名称是普通名称,只是小写并带有下划线而不是空格(这很愚蠢,但这是一个愚蠢的示例,因此只需滚动即可)。您想通过网站的API获取用户的清单;您想要显示“您好,Amadan!这是您的秘诀:”,然后向您展示它的发现。您环顾四周,这里有一个图书馆!太棒了因此,您gem install
并开始编码:
require 'chitter'
print "What is your name? "
name = gets
chitter = Chitter.login_by_name(name)
puts "Hello, #{name}! Here are your cheets:"
puts chitter.cheets
我输入了Amadan
,期望是Hello, Amadan
-但出来的Hello, amadan
是小写的!那怎么会发生?
似乎我们想象中的Chitter
宝石在其login_by_name
中有这行:
name.gsub!(' ', '_').downcase!
在这里,出现意外的字符串突变。可以肯定的是,故障完全在我身上,即假想的Chitter宝石的作者,因为如果那条线是
name = name.gsub(' ', '_').downcase
甚至
name = name.dup.gsub!(' ', '_').downcase!
不会有问题,不会因用户注资而受到侮辱。但是,如果他们的测试套件包含Chitter.login_by_name("testname".freeze)
,那么当这些变异者尝试进行变异时,他们的测试就会遇到异常。
同一件事可能会相反。以以下代码段为例:
require 'chitter'
print "What is your name? "
name = gets
chitter = Chitter.login_by_name(name)
best_friend = chitter.best_friend
best_friend.name.upcase!
puts "Shoutout to your BEST FRIEND, #{best_friend.name}! Here's some of their cheets:"
puts chitter.best_friend.cheets
pandemonium爆发,因为您最好的朋友突然没有Cheeter帐户!为什么?因为显然有人忘记了freeze
返回的对象中的name
chitter.best_friend
。然后,用户用upcase!
修改了该名称,然后库尝试使用大写名称访问cheet,但失败了。问题的根源是
class Cheeter::User
def initialize(name)
@name = name
end
...
attr_reader :name
...
end
如果初始化说@name = name.freeze
,那么我们就不能upcase!
。如果我们使用此方法而不是attr_reader
:
def name
@name.dup
end
然后运行upcase!
没关系,该库使用的名称不会更改。但是由于cheeter.best_friend.name
恰好返回了它正在使用的对象,而没有freeze
,因此在对它进行突变时,我们将猴子扳手投入了操作,认为这是我们的职责
编辑:似乎“颤抖”实际上存在。我对Chitter的创建者表示歉意,而不是重命名我的示例并冒着碰到另一个真实应用程序的风险,所有相似之处都是偶然的,而且我敢肯定,真正的Chitter并不是像我这样可怕地设计的。