提问人:Lennie 提问时间:3/5/2009 最后编辑:dreftymacLennie 更新时间:10/3/2023 访问量:190188
为什么在 Ruby 方法中使用感叹号?
Why are exclamation marks used in Ruby methods?
问:
在 Ruby 中,有些方法有一个问号 (),它问一个问题,比如询问是否包含所讨论的对象,然后返回一个 true/false。?
include?
但是,为什么有些方法有感叹号(),而另一些方法没有呢?!
这是什么意思?
答:
通常,以 结尾的方法表示该方法将修改调用它的对象。Ruby 称这些为“危险方法”,因为它们会改变其他人可能引用的状态。下面是字符串的简单示例:!
foo = "A STRING" # a string called foo
foo.downcase! # modifies foo itself
puts foo # prints modified foo
这将输出:
a string
在标准库中,有很多地方你会看到成对的类似名称的方法,一个有 the,一个没有。没有的方法称为“安全方法”,它们返回原始方法的副本,并对副本进行更改,被调用方保持不变。下面是相同的示例,没有:!
!
foo = "A STRING" # a string called foo
bar = foo.downcase # doesn't modify foo; returns a modified string
puts foo # prints unchanged foo
puts bar # prints newly created bar
这将输出:
A STRING
a string
请记住,这只是一个约定,但很多 Ruby 类都遵循它。它还可以帮助您跟踪代码中修改的内容。
评论
save
save!
ActiveRecord
!通常意味着该方法作用于对象,而不是返回结果。摘自 Programming Ruby 一书:
“危险”或修改接收器的方法可能用尾随的“!”命名。
此命名约定已从 Scheme 中解除。
1.3.5 命名约定
按照惯例,程序的名称 始终返回布尔值 通常以 ''?'' 结尾。此类程序 称为谓语。
按照惯例,程序的名称 将值存储到以前的 分配的位置(参见第 3.4 节) 通常以 ''!'' 结尾。此类程序 称为突变程序。由 convention,则返回的值 突变程序未指定。
评论
感叹号意味着很多事情,有时除了“这很危险,要小心”之外,你无法从中看出很多东西。
正如其他人所说,在标准方法中,它通常用于指示导致对象自身变异的方法,但并非总是如此。请注意,许多标准方法会更改其接收器并且没有感叹号 (, , ),并且某些带有感叹号的方法不会更改其接收器 ()。例如,请参阅此文章。pop
shift
clear
exit!
其他库可能会以不同的方式使用它。在 Rails 中,感叹号通常意味着该方法将在失败时抛出异常,而不是默默地失败。
这是一种命名约定,但许多人以微妙不同的方式使用它。在你自己的代码中,一个好的经验法则是,每当一个方法正在做一些“危险”的事情时,就使用它,特别是当存在两个同名的方法,其中一个比另一个更“危险”时。不过,“危险”几乎可以意味着任何事情。
Bang 可以按以下方式使用,按我个人喜好的顺序使用。
如果活动记录方法不执行此操作,则该方法将引发错误 它说什么,它会。
活动记录方法保存记录,或者方法保存记录 对象(例如条带!
方法执行一些“额外”操作,例如发布到某个位置,或者执行 一些行动。
关键是:只有在你真正考虑过是否 这是必要的,以节省其他开发人员不得不的烦恼 检查你为什么要使用爆炸。
爆炸为其他开发人员提供了两个线索。
调用 方法。
调用该方法时,数据库将被更改。
简单解释:
foo = "BEST DAY EVER" #assign a string to variable foo.
=> foo.downcase #call method downcase, this is without any exclamation.
"best day ever" #returns the result in downcase, but no change in value of foo.
=> foo #call the variable foo now.
"BEST DAY EVER" #variable is unchanged.
=> foo.downcase! #call destructive version.
=> foo #call the variable foo now.
"best day ever" #variable has been mutated in place.
但是,如果您曾经在上面的解释中调用过某个方法,则会永久更改为小写。 不会返回新的字符串对象,而是将字符串替换到原位,完全更改为小写。
我建议你不要使用,除非完全必要。downcase!
foo
downcase!
foo
downcase!
最准确地说,方法与砰!是更危险或更令人惊讶的版本。有许多方法可以在没有 Bang 的情况下发生变异,例如 .destroy
,一般来说,只有在核心库中存在更安全的替代方案时,方法才会发生 Bang。
例如,在 Array 上,我们有 和 ,这两种方法都会改变数组,但如果数组中没有 nil,则返回 nil 而不是 self,这比仅仅返回 self 更令人惊讶。.compact
.compact!
.compact!
我发现的唯一一个非突变方法是's .exit!
,这比因为在进程关闭时无法捕捉更令人惊讶。Kernel
.exit
SystemExit
Rails 和 ActiveRecord 延续了这一趋势,因为它使用 bang 来获得更多“令人惊讶”的效果,例如 .create!,
这在失败时会引发错误。
底线:方法只是更改它们被调用的对象的值,而没有的方法返回一个作的值,而不写出调用方法的对象。!
!
仅当您不打算将原始值存储在调用该方法的变量中时才使用。!
我更喜欢做这样的事情:
foo = "word"
bar = foo.capitalize
puts bar
或
foo = "word"
puts foo.capitalize
而不是
foo = "word"
foo.capitalize!
puts foo
以防万一我想再次访问原始值。
评论
!
User.create!
!
!
!
我喜欢把这看作是一个爆炸性的变化,它摧毁了之前的一切。砰砰声或感叹号表示您正在对代码进行永久保存的更改。
例如,如果你使用 Ruby 的全局替换方法,你所做的替换是永久性的。gsub!
您可以想象的另一种方法是打开文本文件并执行查找和替换,然后保存。 在代码中执行相同的操作。!
如果您来自 bash 世界,另一个有用的提醒是具有进行永久保存更改的类似效果。sed -i
称为“破坏性方法”,它们倾向于改变你所指对象的原始副本。
numbers=[1,0,10,5,8]
numbers.collect{|n| puts n*2} # would multiply each number by two
numbers #returns the same original copy
numbers.collect!{|n| puts n*2} # would multiply each number by two and destructs the original copy from the array
numbers # returns [nil,nil,nil,nil,nil]
我的回答解释了在(RoR)模型验证的背景下,带有感叹号/shebangs的方法的重要性。Ruby
Ruby on Rails
从本质上讲,每当开发人员定义模型验证(此处解释)时,他们的最终目标是拒绝数据库记录更改并引发/抛出相关异常,以防提交无效数据以更新相关记录。
RoR gem 定义了各种模型操作方法(Ruby on Rails 指南)。在这些方法中,该方法是唯一一个无需数据库操作/修改即可触发验证的方法。其余方法将尝试更改数据库。ActiveRecord
valid?
这些方法在运行时触发回调。列表中的一些方法具有带有 shebang 的姊妹方法。两者有什么区别?它与每当记录验证失败时返回的回调形式有关。
没有感叹号/shebang 的方法仅在记录验证失败时返回布尔值 false,而带有 shebang 的方法引发/抛出异常,然后可以在代码中适当地处理该异常。
只是提醒一下,因为我自己也经历过。
在 Ruby 中,改变对象并返回它。否则它将返回 .!
nil
因此,例如,如果您正在对数组进行某种操作,并调用该方法并且没有 nothig 进行压缩,它将返回 ..compact!
nil
例:
arr = [1, 2, 3, nil]
arr.compact!
=> [1, 2, 3]
Run again arr.compact!
=> nil
如果您需要在下一行使用它,最好再次显式返回数组,否则您将获得该值。arr
nil
例:
arr = [1, 2, 3]
arr.compact! => nil
arr # to get the value of the array
0
方法名称末尾的感叹号 (“!”) 是一种命名约定。它们指示该方法可能更危险,执行破坏性操作,或者可以修改它所调用的对象。这是一种提醒开发人员注意方法的特殊行为的方法。感叹号在 Ruby 语言本身中没有特定的含义,但在社区中被广泛使用,以暗示对象的潜在副作用或修改。
示例:def sort!(数组) array.sort!结束
数字 = [3, 1, 2] 排序!(numbers) put numbers.inspect # 输出: [1, 2, 3]
那种!方法对数组进行就地排序并修改原始数字数组。感叹号表示此方法更改了它所操作的对象。
评论