Ruby: 如果引发异常则跳过循环中的元素

Ruby: Skip element in loop if an exception is raised

我有以下方法:

def fetch_something
  @fetch_something ||= array_of_names.inject({}) do |results, name|
    begin
      results[name] = fetch_value!(name)
    rescue NoMethodError, RuntimeError
      next
    end

    results
  end
end

为了它的目的:它为给定的 name 获取一个可能引发错误的值,在这种情况下它将忽略 name 并尝试下一个。

虽然这工作正常,但我从 Rubocop 收到一条错误消息:

Lint/NextWithoutAccumulator: Use next with an accumulator argument in a reduce.

谷歌搜索该错误导致我 http://www.rubydoc.info/gems/rubocop/0.36.0/RuboCop/Cop/Lint/NextWithoutAccumulator 那里说不要省略累加器,这将导致一个看起来像这样的方法:

def fetch_something
  @fetch_something ||= array_of_names.inject({}) do |results, name|
    begin
      results[name] = fetch_value!(name)
    rescue NoMethodError, RuntimeError
      next(name)
    end

    results
  end
end

问题是,此更改破坏了其他工作方法。关于如何解决这个问题有什么想法吗?

更新:演示示例:
array_of_names = ['name1','name2','name3']

def fetch_value!(name)
  # some code that raises an error if the name doesn't correspond to anything
end

fetch_something

# => {'name1' => {key1: 'value1', ...}, 'name3' => {key3: 'value3', ...}}
# 'name2' is missing since it wasn't found durcing the lookup

只需使用each_with_object

def fetch_something
  @fetch_something ||= array_of_names.each_with_object({}) do |name, results|
    results[name] ||= begin
                        fetch_value!(name)
                      rescue NoMethodError, RuntimeError
                      end
  end
end

使用您的示例代码,next(results) 似乎确实解决了我的问题。我使用了一些抛出 KeyError 而不是 NoMethodErrorRuntimeError 的测试代码,但想法仍然相同:

@array_of_names = ['name1','name2','name3']

def fetch_value!(name)
  {'name1' => 'n1', 'name3' => 'n3'}.fetch(name)
end

def fetch_something
  @fetch_something ||= @array_of_names.inject({}) do |results, name|
    begin
      results[name] = fetch_value!(name)
    rescue NoMethodError, RuntimeError, KeyError
      next(results)
    end

    results
  end
end

p fetch_something

此代码输出:

{"name1"=>"n1", "name3"=>"n3"}

此外,我同意@Алексей Кузнецов 的观点,即 each_with_object 可能是每当您的块代码改变您尝试构建的数据结构时的方法。所以我更喜欢 fetch_something 的实现可能更像这样:

def fetch_something
  @fetch_something ||= @array_of_names.each_with_object({}) do |name, results|
    begin
      results[name] = fetch_value!(name)
    rescue NoMethodError, RuntimeError, KeyError
      # error handling
    end
  end
end

请注意,在我的示例中,begin/endresults[name] 的赋值之外,与 @Алексей Кузнецов 的示例形成对比每次发生异常时都会将 nil 分配给散列。