Ruby将String隐式转换为Integer(typeError)

时间:2018-08-31 16:16:52

标签: ruby yaml

我正在尝试使用YAML文件,从中读取并将其写入值列表。在此脚本的第一次运行中,正确创建了yaml文件,但是在第二次运行时,它将引发转换TypeError,我不知道要修复。

db_yml = 'store.yml'

require 'psych'
begin
    if File.exist?(db_yml)
        yml = Psych.load_file(db_yml)
        puts "done load"        

        yml['reminders']['reminder_a'] = [123,456] 
        yml['reminders']['reminder_b'] = [457,635,123]
        File.write(db_yml, Psych.dump(yml) ) 
    else 
      #the file does not exist yet, create an empty one.
        File.write(db_yml, Psych.dump(
        {'reminders' => [
            {'reminder_a'=> [nil]}, 
            {'reminder_b'=> [nil]}
        ]}
  )) #Store
    end
rescue IOError => msg  
  # display the system generated error message  
  puts msg 
end

在第一次运行时产生文件store.yml:

---
reminders:
- reminder_a:
  - 
- reminder_b:
  - 

到目前为止,一切都很好。但随后在第二次运行中,它失败并

done load
yamlstore.rb:23:in `[]=': no implicit conversion of String into Integer (TypeError)
        from yamlstore.rb:23:in `<main>'

你能告诉我我要去哪里了吗?

2 个答案:

答案 0 :(得分:6)

该错误消息表明您正在传递String,而Ruby希望它可以隐式转换为Integer。当索引到Integer时,Ruby期望可以隐式转换为Array的东西的第一位。因此,只要您看到此错误消息,就可以99%确保您正在以自己认为是Array但不是的索引Integer或正在索引{{ 1}},您认为还有其他东西(很可能是Array)。 (另一种可能性是您尝试使用HashIntegers的混合进行算术。)

仅仅因为Ruby是一种动态类型的编程语言,并不意味着您不需要关心类型。特别是,YAML是一种(有点)类型的序列化格式。

您要创建的文件的类型如下所示:

Strings

但是,您正在访问它,就像它是这样键入的:

Map<String, Sequence<Map<String, Sequence<Int | null>>>>

更具体地说,您正在创建与键Map<String, Map<String, Sequence<Int | null>>> 相对应的值,作为序列(在YAML术语中,是'reminders'在Ruby中)< em> maps (Array es)。 HashArray索引。

但是,您正在使用Integers对其进行索引,就好像它是String

因此,您需要更改访问值的方式:

Hash

或者像这样更改初始化文件的方式:

yml['reminders'][0]['reminder_a'] = [123, 456]
#               ↑↑↑

yml['reminders'][1]['reminder_b'] = [457,635,123]
#               ↑↑↑

以使生成的YAML文档如下所示:

File.write(db_yml, Psych.dump(
{ 'reminders' => {
#                ↑
    'reminder_a' => [nil],
#  ↑                     ↑
    'reminder_b' => [nil]
#  ↑                     ↑
}

答案 1 :(得分:4)

YAML文件没有任何问题。但是,您创建的文件具有以下结构:

yaml = {
  'reminders' => [
    {'reminder_a'=> [nil]}, 
    {'reminder_b'=> [nil]}
  ]
}

请注意,yaml['reminders']的内容是一个数组。出问题的地方在这里:

reminders = yaml['reminders']
reminder_a = reminders['reminder_a'] # <= error

# in the question example:
# yml['reminders']['reminder_a'] = [123,456]

由于reminders是一个数组,因此无法通过将字符串作为索引传递来访问它。您有2个选择:

  1. 我认为最好的选择(如果要通过键访问提醒)是将结构更改为使用哈希而不是数组:

    yaml = {
      'reminders' => {
        'reminder_a'=> [nil], 
        'reminder_b'=> [nil]
      }
    }
    

    使用上述结构,您可以通过以下方式访问提醒:

    yaml['reminders']['reminder_a']
    
  2. 有些笨拙,使用正确的键找到数组元素:

    yaml['reminders'].map! do |reminder|
      reminder['reminder_a'] = [123,456] if reminder.key? 'reminder_a'
      reminder['reminder_b'] = [457,635,123] if reminder.key? 'reminder_b'
      reminder
    end