Ruby: метод не возвращает ожидаемый результат - PullRequest
1 голос
/ 11 октября 2019

Я пытаюсь создать программу, которая имитирует проверку в магазине. Однако мой метод 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

Ответы [ 4 ]

2 голосов
/ 11 октября 2019

Лучше использовать метод find :

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

UPDATE

В рубине предпочтительным является 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
1 голос
/ 11 октября 2019

Ruby всегда возвращает результат выражения, оцененного в методе. В случае AddItem это each. Enumerable#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 возвращает элемент массива, для чегоблок возвращает истинное значение

0 голосов
/ 12 октября 2019

Если вы не явно return что-то из метода (или next что-то из блока), тогда последнее вычисленное выражение становится возвращаемым значением метода(блок, лямбда, тело определения модуля, тело определения класса).

Поскольку вы не явно return из AddItem, последнее вычисленное выражение будет возвращаемымстоимость. Последнее выражение, которое оценивается, это:

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

Другими словами, возвращаемое значение AddItem будет возвращаемым значением @item.each. Согласно документации Array#each, возвращаемое значение - это просто Array, к которому был вызван each. (Обратите внимание, что это на самом деле не относится к Array#each, это общий контракт из each, так что это верно для всех реализаций each.)

Это имеет смысл: цель each - выполнить побочный эффект для каждого элемента коллекции. На самом деле не имеет полезного возвращаемого значения. Итак, два разумных возвращаемых значения будут nil и self, и разработчики библиотеки выбрали 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 = 0 делает в AddItem?
  • Класс называется Action, что является очень общим именем и мало что говорит о том, что он делает.
  • Кажется, он не выполняет большую часть действия,хотя.
  • Когда вы создаете экземпляр Action, вы назначаете его переменной с именем customer. Однако, похоже, что он не делает много «привычных» вещей.
  • В конце концов, вы кладете клиента в корзину. Представьте себе, это был настоящий супермаркет. Так ли это в реальном мире?

И последнее замечание: стандартный стиль кодирования сообщества Ruby состоит в использовании snake_case для методов, локальных переменных, переменных экземпляра, переменных класса и глобальныхпеременные. PascalCase для констант, которые указывают на классы или модули, SCREAMING_SNAKE_CASE для других констант. Мы не используем camelCase.

0 голосов
/ 11 октября 2019

В Ruby последняя переменная, определенная в методе, возвращается автоматически. Так как вы определяете @item последнее, это то, что вы получаете обратно. Проблема в том, что вы перебираете @item, но ничего не делаете с результатом, поэтому @item остается неизменным.

Предполагая, что @item на самом деле должно быть множественным числом @items ?, я представляю, что вы на самом деле хотитедля этого нужно использовать select вместо каждого.

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

Это вернет массив элементов, которые вернули true из x[:name] === item

Затем снова имя метода AddItem didn 't действительно представляет то, что на самом деле делает метод, но это другая история:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...