【问题标题】:Ruby: Method not returning expected outputRuby:方法未返回预期输出
【发布时间】:2020-02-08 20:46:57
【问题描述】:

我正在尝试创建一个模拟商店结账的程序。但是我的AddItem 方法返回类变量@item 而不仅仅是它找到的单数项。因此,一旦添加了所有项目,它将能够显示这些项目的总数量。

class Action
  def initialize(customerMoney)
    @money = customerMoney
    @item = [{ name: :milk, price: 2.99 }, { name: :eggs, price: 1.50 }, { name: :bread, price: 2.00 }]
  end

  def CheckPrice(item)
    @item.each do |x|
      return x[:price] if x[:name] == item
    end
  end

  def AddItem(item)
    i = 0
    @item.each do |x|
      if x[:name] == item
        x
      end
    end
  end

  def CheckTotal(basket)
    total = 0
    basket.each do |x|
      total += x[:price]
    end
    puts total
  end
end

myBasket = []
customer = Action.new(20)
myBasket.append(customer.AddItem(:bread))

p myBasket

【问题讨论】:

    标签: arrays ruby class


    【解决方案1】:

    Ruby 总是返回在方法中求值的表达式的结果。如果是AddItem,则为eachEnumerable#each 返回被枚举的整个集合。您需要添加一个找到的元素作为方法的最后一行:

       def AddItem(item)
           i = 0 
           found = nil
           @item.each do |x|
               if x[:name] == item
                   found = x
               end
           end
           found # <<<<<<<<< returning found
       end
    

    顺便说一句。在 ruby​​ 中,方法以 snake_case 而不是 CamelCase 命名。 @item 也是一个实例(不是类)变量。

    顺便说一句,您也可以对 find 做同样的事情:

       def AddItem(item)
         @item.find do |x|
           x[:name] == item
         end  
       end
    

    find 返回数组元素,块返回真值

    【讨论】:

      【解决方案2】:

      最好使用find方法:

      def AddItem(item)
        @item.find{ |x| x[:name] == item }
      end
      

      更新

      在 ruby​​ 中,snake_case 是首选。我已经用 ruby​​ 方法编辑了代码。

      class Action
        def initialize(customer_money)
          @money = customer_money
          @items = [{ name: :milk, price: 2.99 }, { name: :eggs, price: 1.50 }, { name: :bread, price: 2.00 }]
        end
      
        def check_price(item)
          @items.find{ |x| x[:name] == :bread }[:price]
        end
      
        def add_item(item)
          @items.find{ |x| x[:name] == item }
        end
      
        def check_total(basket)
          puts basket.sum{ |x| x[:price] }
        end
      end
      

      【讨论】:

        【解决方案3】:

        在 Ruby 中,方法中定义的最后一个变量会自动返回。由于您最后定义了@item,这就是您要返回的内容。问题是您正在循环通过 @item 但没有对结果做任何事情,所以 @item 保持不变。

        假设 @item 实际上应该是复数 @items?,我想你真正想要做的是使用 select 而不是 each。

        def AddItem(item)
          @items.select {|x| x[:name] === item}
        end
        

        这将返回一个从x[:name] === item返回true的项目数组

        然后AddItem 方法的名称并不能真正代表该方法实际在做什么,但那是另一回事:)

        【讨论】:

          【解决方案4】:

          如果您不明确 return 来自方法(或next 来自块),则最后评估的表达式 成为返回值方法(块、lambda、模块定义体、类定义体)。

          由于您显式地从return 转换为AddItem,因此计算的最后一个表达式将是返回值。最后一个被计算的表达式是:

          @item.each do |x|
            if x[:name] == item
              x
            end
          end
          

          换句话说,AddItem 的返回值将是@item.each 的返回值。根据the documentation of Array#each,返回值就是调用eachArray。 (请注意,这实际上并不特定于Array#each,它是each通用合同,因此对于each所有 实现都是如此。)

          这是有道理的:each 的目的是对集合的每个元素执行副作用。它实际上并没有 有用的返回值。因此,两个合理的返回值将是nilself,而库设计者选择了self。 (大概是为了允许方法链接,我不知道。)

          下一个问题是你的块实际上并没有做任何事情。请记住,each 的目的是对每个元素执行副作用,但您的块没有任何副作用!如果你想做任何有用的事情,你需要一个副作用(比如修改外部变量绑定):

          def AddItem(item)
            return_value = nil
          
            @item.each do |el|
              return_value = el if el[:name] == item
            end
          
            return_value
          end
          

          或者,您可以直接return找到的项目:

          def AddItem(item)
            @item.each do |el|
              return el if el[:name] == item
            end
          end
          

          但实际上,您要做的是找到第一个匹配项:

          def AddItem(item)
            @item.find {|el| el[:name] == item }
          end
          

          请注意,您的代码有很多令人困惑的地方:

          • 您有两个方法都命名为CheckSomething,但这两种方法做的事情完全不同。
          • 此外,这两种方法都没有实际检查某些内容,一种方法打印某些内容,另一种方法查找某些内容。
          • 您的方法AddItem 的作用与CheckPrice 完全相同,但名称完全不同。此外,它以完全不同的方式做事。 (这就是它不起作用的原因。)
          • 同样,命名:AddItem 实际上并没有添加任何内容。
          • 另外,i = 0AddItem 中做什么?
          • 该类名为Action,这是一个非常通用的名称,并没有说明它在做什么。
          • 不过,它似乎没有多大作用。
          • 实例化Action 时,将其分配给名为customer 的变量。但是,它似乎也没有做太多“客户”的事情。
          • 最后,您将客户放入篮子。想象一下,这是一个现实世界的超市。这就是它在现实世界中的运作方式吗?

          最后一点:标准的 Ruby 社区编码风格是使用snake_case 表示方法、局部变量、实例变量、类变量和全局变量。 PascalCase 用于指向类或模块的常量,SCREAMING_SNAKE_CASE 用于其他常量。我们不使用camelCase

          【讨论】:

            猜你喜欢
            • 2017-10-21
            • 1970-01-01
            • 1970-01-01
            • 2021-08-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多