在回应related question时,@ DanRio问了这个follow-up question:
如果数组中的元素为nil,则使用array.map!(&:upcase)会给出一个无方法错误。我该如何解决这个问题?
因为这超出了原始问题的范围,我将代表他在此处发布。
这是用户询问的代码片段:
array = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
array.map!(&:upcase)
答案 0 :(得分:2)
在原始问题中,数组中的值都是String对象。但是,如果阵列的内容没有提前知道,那么当然可能有些元素可能是零。由于nil不会#respond_to?:upcase,数组中的任何nils都会触发您看到的NoMethodError异常。
有很多方法可以解决这个问题,包括:
我将重点关注答案其余部分的最后一项。
哪个答案最好取决于上下文,但我推荐常见案例的安全导航操作符。除了发行说明之外,我无法在任何地方找到它,但它的工作原理与Rails的Object#try方法非常相似。
不是直接使用map! &:upcase
映射每个元素,而是使用安全导航仅在响应它的对象上调用#upcase。例如:
array = ["Monday", "Tuesday", "Wednesday", "Thursday", nil, "Friday"]
array.map! { |e| e&.upcase }
#=> ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", nil, "FRIDAY"]
答案 1 :(得分:0)
以下是不同方法的基准:
require 'benchmark'
arr = 100_000.times.map { nil }
Benchmark.bm do |bm|
bm.report("compact then upcase\n") do
arr.compact.each &:upcase
end
bm.report("save nagivation then upcase\n") do
arr.each { |y| y&.upcase }
end
bm.report("respond_to then upcase\n") do
arr.each { |y| y.upcase if y.respond_to?(:upcase) }
end
bm.report("boolean check then upcase\n") do
arr.each { |y| y && y.upcase }
end
end
和结果:
user system total real
compact then upcase
0.000000 0.000000 0.000000 ( 0.000912)
save nagivation then upcase
0.020000 0.000000 0.020000 ( 0.005030)
respond_to then upcase
0.000000 0.000000 0.000000 ( 0.009824)
boolean check then upcase
0.000000 0.000000 0.000000 ( 0.005254)
您可以看到契约是最快的,但其结果与其他结果之间存在重要差异。 不在结果中包含任何nil值,如果跳过某些项,则结果将是不同的长度。
所以我想说如果你想让结果不保留nil
,那么使用compact,否则使用布尔或安全导航,它们的表现大致相同。