【问题标题】:Ruby syntax: break out from 'each.. do..' blockRuby 语法:从 'each.. do..' 块中分离出来
【发布时间】:2011-12-14 09:46:49
【问题描述】:

我正在开发一个 Ruby on Rails 应用程序。我的问题更多关于 Ruby 语法。

我有一个带有类方法self.check的模型类:

class Cars < ActiveRecord::Base
  ...
  def self.check(name)
     self.all.each do |car|
          #if result is true, break out from the each block, and return the car how to...
          result = SOME_CONDITION_MEET?(car) #not related with database
     end

     puts "outside the each block."
  end
end

我想停止/突破each一旦resulttrue(如果car.name 则打破each 块与name 参数once 相同)并返回导致true 结果的car。如何在 Ruby 代码中突围?

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-3 ruby-on-rails-3.1


    【解决方案1】:

    您可以使用 break 关键字来中断。例如

    [1,2,3].each do |i|
      puts i
      break
    end
    

    将输出1。或者如果你想直接返回值,使用return

    既然你更新了问题,这里是代码:

    class Car < ActiveRecord::Base
      # …
    
      def self.check(name)
        self.all.each do |car|
          return car if some_condition_met?(car)
        end
    
        puts "outside the each block."
      end
    end
    

    尽管您也可以为此目的使用 Array#detectArray#any?

    【讨论】:

      【解决方案2】:

      我提供了一个错误的示例代码。我不是直接找到或检查的东西 从数据库。我只需要一种方法来摆脱“每个”块,如果 某些条件满足一次并返回导致真实的“汽车” 结果。

      那么你需要的是:

      def check(cars, car_name)
        cars.detect { |car| car.name == car_name }
      end
      

      如果您只想知道是否有任何具有该名称的汽车,那么您可以使用Enumerable#any?。根据经验,Enumerable#each 仅用于执行副作用,而不是执行逻辑。

      【讨论】:

        【解决方案3】:

        你可以使用include?方法。

        def self.check(name)
          cars.include? name
        end
        

        如果name 存在于cars 数组中,则include? 返回true,否则返回false

        【讨论】:

          【解决方案4】:

          您可以使用break,但您尝试做的事情可以更轻松地完成,如下所示:

          def self.check(name)
            return false if self.find_by_name(name).nil?
            return true
          end
          

          这使用数据库。您正在尝试在数据库可以更好地处理它的地方使用 Ruby。

          你也可以使用break条件:

          break if (car.name == name)
          

          【讨论】:

          • 我提供了一个错误的示例代码。我不是直接从数据库中查找或检查某些内容。如果某些条件满足一次,我只需要一种方法从“每个”块中突破并返回导致真实结果的“汽车”。
          • 好吧,你甚至可以改进这个:def self.check(name); self.where(:name =&gt; name).any?; end
          • 第一个sn-p可以写成:!!self.find_by_name(name).
          • @tokland => 我没有编辑答案,因为线程开启者只是将其作为示例发布,核心问题是如何打破每个而不是如何检查同名数据集是否已经存在.但是任何地方都不错的代码。我从来没有想过编码中的双重否定^^
          • @Mellon:那么您应该更新问题以反映您真正想要的内容。
          【解决方案5】:

          我必须做同样的事情,而我正在画一个空白。因此,尽管这是一个非常古老的问题,但这是我的答案:

          注意:此答案假定您不想返回数组中存在的项目,而是对项目进行一些处理并返回结果。这就是我的方式最初阅读了这个问题,我现在意识到这是不正确的——尽管可以很容易地修改这种方法来达到这种效果(break iteminsead of break output

          由于从街区返回是狡猾的(没有人喜欢它,而且我认为规则即将改变,这使得它更加令人担忧)这是一个更好的选择:

          collection.inject(nil) do |_acc, item|
            output = expensive_operation(item)
            break output if output
          end
          

          请注意,有很多变体;例如,如果您不想要一个附带变量,并且不介意在某些情况下启动第二个循环,您可以像这样反转它:

          collection.inject(nil) do |acc, item|
            break acc if acc
            expensive_operation(item)
          end
          

          【讨论】:

            猜你喜欢
            • 2011-01-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-05-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多