我正在尝试使用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>'
你能告诉我我要去哪里了吗?
答案 0 :(得分:6)
该错误消息表明您正在传递String
,而Ruby希望它可以隐式转换为Integer
。当索引到Integer
时,Ruby期望可以隐式转换为Array
的东西的第一位。因此,只要您看到此错误消息,就可以99%确保您正在以自己认为是Array
但不是的索引Integer
或正在索引{{ 1}},您认为还有其他东西(很可能是Array
)。 (另一种可能性是您尝试使用Hash
和Integers
的混合进行算术。)
仅仅因为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)。 Hash
被Array
索引。
但是,您正在使用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个选择:
我认为最好的选择(如果要通过键访问提醒)是将结构更改为使用哈希而不是数组:
yaml = {
'reminders' => {
'reminder_a'=> [nil],
'reminder_b'=> [nil]
}
}
使用上述结构,您可以通过以下方式访问提醒:
yaml['reminders']['reminder_a']
有些笨拙,使用正确的键找到数组元素:
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