如何在Ruby中向哈希添加值

如何在Ruby中向哈希添加值,ruby,methods,hash,Ruby,Methods,Hash,我在这个主题上做了很多研究,但在我尝试的每种情况下,哈希中的值似乎都会被替换。在此人选择输入新ID后,我希望将下一个人的姓名和年龄添加到哈希中。有人能给我解释一下为什么要替换键和值吗 class Person def initialize(name, age) if name != nil || age != nil if @people != nil @people[name.__id__] = age.__id__ else

我在这个主题上做了很多研究,但在我尝试的每种情况下,哈希中的值似乎都会被替换。在此人选择输入新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

我认为键值对被替换的原因是:

initialize
方法中的语句

if @people != nil
将始终计算为
false
<代码>初始化在创建新对象时被调用,因此默认情况下,
@people
尚未定义或设置,因此每次调用

 person = Person.new(inputname, inputage)
它创建了一个新的
,而不是将这个新的人添加到一个现有的散列中(我认为您正在尝试这样做)

如果将
people
设置为类变量(
@@people
),可能会起作用,但似乎您只是想在主程序中创建一个哈希,然后在其中添加新的条目

像这样的

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

让我解释一下为什么您会遇到所描述的问题,并为您如何更改代码提供一些建议

班级人员

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
在类
Person
中,您需要在类级别保存人员列表,这意味着使用类实例变量(例如
@people
)或类变量(例如
@@people
)。我和大多数鲁比学生一样,更喜欢前者。(原因超出了这个答案的范围,但你只需在谷歌上搜索“Ruby‘class instance variables’vs‘class variables’”,就可以找到很多关于这个主题的文章。你只需输入内部引号,就可以缩小搜索范围。)

要定义类实例变量@people,我们只需按如下方式输入它:

class Person
  @people = {}
  class << self
    attr_accessor :people
  end
  def initialize(name, age)
    self.class.people[name] = age
  end
end
将元素添加到hash@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
退出循环。我非常喜欢这种构造,与循环
相比,当…
直到…
时,部分原因是它避免了需要输入一个开始条件进入循环,然后在循环中重复相同的条件。我也只是觉得它看起来更干净

当您离开循环时,在循环中创建的任何变量都不再存在,因此如果您想要变量的值(例如,
name
age
),则必须在循环的开头之外引用该变量。这就是为什么(也是唯一的原因)我有
name=nil
age=nil
。它不必是
nil
;我可以把它们初始化成任何东西

使用
案例
语句

获取年龄的循环使用以下case语句:

case age
when /^\d+$/ && ('10'..'120')
  ...
end  
这需要一些解释。
case
语句使用,而不是获取真实值。因此,
当/^\d+$/
相当于:

/^\d+$/ === age
这和

/^\d+$/ =~ age
('10'..'120').cover?(age)
正则表达式只是确保所有年龄字符都是数字(例如,“39”)

同样地

('10'..'120') === age

/^\d+$/ =~ age
('10'..'120').cover?(age)
零碎物品

我使用了
String#strip
来代替
String#chomp
。这两种方法都会删除结尾的换行符,但
strip
也会删除用户可能在输入字符串的开头或结尾输入的空格

对于字符串,我主要使用单引号,但字符串插值需要双引号。例如,我最初编写了
put'name is#{name}
。打印的
name is#{name}
。将其更改为
put'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

@people
是一个实例变量,因此每个实例都有一个实例变量。每个实例只包含一个键/值对。我猜您希望将与所有实例变量关联的名称和年龄存储在
@people
中。如果是这样,您需要将
@people
设置为类实例变量(或使用类变量,如@@people)。你需要重新构造你的类,因为你想保持状态,你需要将
attr\u reader:people
更改为
attr\u accessor:people
,这样你就可以改变people散列的结构,我也不认为你使用
\uu id\uuu
是正确的或必要的,并且移动
MainInit的初始化方法中的所有逻辑
进入另一个方法,只在其中留下
@people=Person.new(nil,nil)
,然后你可以调用你创建的新方法,例如
mainit.new.new\u method
,而不是
mainit.new
,在你的脚本末尾我很快会给你另一个答案。