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
4 Réponses :
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é
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 :)
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:
CheckSomething , mais les deux méthodes font des choses complètement différentes. 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.) AddItem n'ajoute en fait rien. i = 0 dans AddItem ? Action , qui est un nom très générique et ne dit pas grand-chose sur ce qu'elle fait. Action , vous l'affectez à une variable nommée customer . Cependant, il ne semble pas non plus qu'il fasse beaucoup de choses "personnalisées". 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.