1
votes

Ruby: méthode ne renvoyant pas la sortie attendue

J'essaye de créer un programme qui simule une sortie dans un magasin. Cependant, ma méthode AddItem retourne la variable de classe @item plutôt que simplement l'élément singulier qu'elle a trouvé. Ainsi, une fois tous les articles ajoutés, il pourra afficher le montant total de ces articles.

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


0 commentaires

4 Réponses :


1
votes

Ruby renvoie toujours le résultat de l'expression évaluée dans une méthode. Dans le cas de AddItem c'est chacun . Enumerable # each renvoie la collection entière qui était sous énumération. Vous devez ajouter un élément trouvé comme dernière ligne de la méthode:

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

Btw. dans ruby, les méthodes sont nommées avec snake_case et non avec CamelCase . @item est également une variable d'instance (et non de classe).

Btw, vous pouvez faire la même chose avec find:

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

as find renvoie l'élément de tableau pour lequel le bloc renvoie une valeur de vérité


0 commentaires


0
votes

Dans Ruby, la dernière variable définie dans une méthode est automatiquement renvoyée. Puisque vous définissez @item en dernier, c'est ce que vous obtenez. Le problème est que vous parcourez @item mais que vous ne faites rien avec le résultat donc @item reste inchangé.

En supposant que @item devrait en fait être au pluriel @items ?, J'imagine que ce que vous voulez faire est d'utiliser select plutôt que each.

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

Cela renverra un tableau des éléments qui ont renvoyé vrai de x [: name] === élément

Là encore, le nom de la méthode AddItem ne représente pas vraiment ce la méthode est en train de faire, mais c'est une autre histoire :)


0 commentaires

0
votes

Si vous ne retournez pas explicitement quelque chose d'une méthode (ou next quelque chose d'un bloc), alors la dernière expression évalué devient la valeur de retour de la méthode (bloc, lambda, corps de définition de module, corps de définition de classe).

Puisque vous ne retournez pas explicitement à partir de AddItem , la dernière expression évaluée sera la valeur de retour. La dernière expression évaluée est:

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

En d'autres termes, la valeur de retour de AddItem sera la valeur de retour de @ item.each . Selon la documentation de Array # each , la valeur de retour est simplement le Array sur lequel chaque a été appelé. (Notez que ce n'est en fait pas spécifique à Array # each , c'est le contrat général de each , donc c'est vrai pour toutes implémentations de each.)

Cela a du sens: le but de each est d'exécuter un effet secondaire pour chaque élément de la collection. Il n'a pas vraiment de valeur de retour utile. Ainsi, les deux valeurs de retour raisonnables seraient nil et self , et les concepteurs de la bibliothèque ont choisi self . (Vraisemblablement, pour permettre le chaînage de méthodes, je ne sais pas.)

Le problème suivant est que votre bloc ne fait rien. N'oubliez pas que le but de chaque est d'exécuter un effet secondaire pour chaque élément, mais votre bloc n'a aucun effet secondaire! Si vous vouliez faire quelque chose d'utile, vous auriez besoin d'un effet secondaire (comme la modification d'une liaison de variable externe):

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

Alternativement, vous pouvez retourner code> l'élément trouvé directement:

def AddItem(item)
  return_value = nil

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

  return_value
end

Mais en réalité, ce que vous voulez faire est de trouver le premier élément correspondant:

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

Notez qu'il y a beaucoup de choses déroutantes à propos de votre code:

  • Vous avez deux méthodes qui sont toutes deux nommées CheckSomething , mais les deux méthodes font des choses complètement différentes.
  • De plus, aucune des deux méthodes ne vérifie réellement quelque chose, une méthode imprime quelque chose et l'autre trouve quelque chose.
  • Votre méthode AddItem fait exactement la même chose que CheckPrice , mais son nom est complètement différent. En outre, il fait les choses d'une manière complètement différente. (C'est pourquoi cela ne fonctionne pas.)
  • Encore une fois, nommer: AddItem n'ajoute en fait rien.
  • De plus, que fait cet i = 0 dans AddItem ?
  • La classe s'appelle Action , qui est un nom très générique et ne dit pas grand-chose sur ce qu'elle fait.
  • Cela ne semble pas faire beaucoup d’action.
  • Lorsque vous instanciez Action , vous l'affectez à une variable nommée customer . Cependant, il ne semble pas non plus qu'il fasse beaucoup de choses "personnalisées".
  • En fin de compte, vous mettez le client dans un panier. Imaginez, c'était un supermarché du monde réel. Est-ce ainsi que cela fonctionne dans le monde réel?

Et une dernière remarque: le style de codage standard de la communauté Ruby consiste à utiliser snake_case pour les méthodes, les variables locales, les variables d'instance, les variables de classe et les variables globales. PascalCase est pour les constantes qui pointent vers des classes ou des modules, SCREAMING_SNAKE_CASE pour les autres constantes. Nous n'utilisons pas camelCase.


0 commentaires