我已就此主题做了大量研究,但在我尝试的每种情况下,值都会在哈希值中被替换。在该人选择输入新ID之后,我希望将下一个人的姓名和年龄添加到哈希中。有人可以向我解释为什么要更换键和值吗?
class Person
def initialize(name, age)
if name != nil || age != nil
if @people != nil
@people[name.__id__] = age.__id__
else
@people = {name => age}
end
else
puts "Invalid credentials."
end
end
attr_reader :people
end
class MainInit
def initialize()
options = ["y", "yes", "n", "no"]
choice = "y"
while choice.downcase == "y" || choice.downcase == "yes"
p "Enter Name:"
inputname = gets.chomp
p inputname
p "Enter Age:"
inputage = gets.chomp
p inputage
person = Person.new(inputname, inputage)
p person.people
p "Enter another ID?"
choice = gets.chomp
until options.include? choice.downcase
p "Invalid Choice"
p "Enter another ID?"
choice = gets.chomp
end
end
end
end
MainInit.new
答案 0 :(得分:1)
我认为键值对被替换的原因是:
initialize
方法
if @people != nil
将始终评估为false
。创建新对象时会调用initialize
,因此默认情况下@people
尚未定义或设置,因此每次调用时都会
person = Person.new(inputname, inputage)
它会创建一个新的Person
,而不是将新人添加到现有的哈希(这是我认为你想要做的事情)。
如果你使people
成为一个类变量(@@people
),可能有效,但似乎你只想在主程序中创建一个Hash然后再添加那里的新条目。
这样的事情
people = Hash.new # Or even just people = {}
然后当你有一个新的名字/年龄条目要添加
people[name] = age
我没有尝试过,但我认为你的整个程序应该简化为:
people = Hash.new
options = ["y", "yes", "n", "no"]
choice = "y"
while choice.downcase == "y" || choice.downcase == "yes"
p "Enter Name:"
inputname = gets.chomp
p inputname
p "Enter Age:"
inputage = gets.chomp
p inputage
#person = Person.new(inputname, inputage)
people[inputname] = inputage
person = people[inputname]
p person.people
p "Enter another ID?"
choice = gets.chomp
until options.include? choice.downcase
p "Invalid Choice"
p "Enter another ID?"
choice = gets.chomp
end
答案 1 :(得分:0)
让我们解释为什么你遇到了你描述的问题,并提供了一些关于如何更改代码的建议。
<强> class Person
强>
在类Person
中,您需要在类级别保存人员列表,这意味着使用类实例变量(例如@people
)或类变量(例如, @@people
)。我和大多数Rubie在偏爱前者。 (原因超出了这个答案的范围,但你会发现很多关于这个主题的写作,只需谷歌搜索,“Ruby'类实例变量'与'类变量'”。内部引号 - 你输入的唯一 - - 帮助缩小搜索范围。)
要定义类实例变量@people,我们只需输入如下:
class Person
@people = {}
class << self
attr_accessor :people
end
def initialize(name, age)
self.class.people[name] = age
end
end
@
表示它是一个实例变量。一旦Ruby读取class Person
,它就会将self
设置为Person
。然后它读取@people = {}
并使其成为Person
的实例变量。相比之下,如果您要在@person
方法中初始化initialize
,那么self
将是Person
的实例,因此@person
将是一个普通的实例变量。 (旁白:我们可以同时拥有一个类实例变量@person
和一个实例变量@person
,Ruby会将它们视为与@night
和@day
不同。)< / p>
为了让对象访问@people
,我们定义了一个访问者。如果我们刚刚输入attr_accessor :person
,Ruby将为常规实例变量@person
创建一个访问器。相反,我们输入class << self
,它指示Ruby将与后面的end
之后的内容相关联。
每次创建一个新的Person实例时,对于给定的name
和age
,
self.class.people[name] = age
向哈希@person添加一个元素,因为self.class
是Person
而people
是访问者。
现在看一下班级MainInit
班级MainInit
class MainInit
def initialize
loop do
name = nil
loop do
print 'Enter Name: '
name = gets.strip
break unless name.empty?
end
puts "name is #{name}"
age = nil
loop do
print 'Enter Age: '
age = gets.strip
case age
when /^\d+$/ && ('10'..'120')
break
else
puts 'age must be between 10 and 120'
end
end
puts "age is #{age}"
person = Person.new(name, age)
puts "people is now #{Person.people}"
loop do
print "Enter another ID? "
case gets.chomp.downcase
when 'n', 'no'
return
when 'y', 'yes'
break
else
puts 'Invalid choice'
end
end
end
end
end
loop do...end
您看到我在几个地方使用loop do...end
和break
退出循环。与循环while...
或或until...
相比,我是这个结构的忠实粉丝,部分原因是它避免了进入循环进入循环然后重复相同条件的需要循环。我也觉得它看起来更干净。
当您离开循环时,循环内创建的任何变量都不再存在,因此如果您想要变量的值(例如,name
和age
),则必须在开头之外引用变量的循环。这就是为什么(也是唯一的原因)我有name = nil
和age = nil
。它不一定是nil
;我可以将它们初始化为任何东西。
使用case
声明
获得年龄的循环使用此案例陈述:
case age
when /^\d+$/ && ('10'..'120')
...
end
这需要一些解释。 case
语句使用String#===而不是String#==来获取真值。因此when /^\d+$/
相当于:
/^\d+$/ === age
与
相同/^\d+$/ =~ age
正则表达式只是确保所有年龄字符都是数字(例如“39”)。
类似地,
('10'..'120') === age
与
相同('10'..'120').cover?(age)
赔率和结束
我使用String#strip
代替String#chomp
。两者都删除了结尾换行符,但strip
也删除了用户可能在输入字符串的开头或结尾输入的空格。
对于字符串,我主要使用单引号,但字符串插值需要双引号。例如,我最初写了puts 'name is #{name}'
。打印name is #{name}
。将其更改为puts "name is #{name}"
后,它正确打印name is Debra
。
示例强>
MainInit.new
Enter Name: Debra
name is Debra
Enter Age: 29
age is 29
people is now {"Debra"=>"29"}
Enter another ID? y
Enter Name: Billy-Bob
name is Billy-Bob
Enter Age: 58
age is 58
people is now {"Debra"=>"29", "Billy-Bob"=>"58"}
Enter another ID? u
Invalid choice
Enter another ID? n