我正在学习Ruby(使用Pickaxe书),我遇到了一些与块操作有点混淆,有点像这样:
class CsvReader
def initialize
@book_in_stock = []
end
def read_in_csv_data(csv_file_name)
CSV.foreach(csv_file_name, headers: true) do |row| # 1.
@book_in_stock << BookinStock.new(row["ISBN"], row["Amount"]) # 2.
end
end
end
我在评论“#1”和“#2”上存在混淆,我不明白我们如何从包含数据的“test.csv”的csv_file_name获取“123”和“456”:
"ISBN","Amount"
"123","456"
行[“ISBN”]如何知道下一行对应它?所有块都以这种方式运行吗?他们真的叫什么?有人可以更好地解释一下吗?
答案 0 :(得分:2)
块是用于描述闭包的ruby习惯用法,或者是具有自己范围的代码块(它不需要知道代码的其他部分)。块有两种样式,如果代码在多行上,则使用do语法(给定数据结构或一些名为@entries的可枚举)
@entries.each do |entry|
#do something
end
如果它在一行上,你可以简化块
@entries.each{|entry| execute something here
}
显式地,代码块所做的是一次传入一个条目,分配给条目并对其执行操作。它就像一个匿名的内部功能。
起初他们有点难以理解,但真正有用并且遍布整个红宝石世界。我们有时会患有肠炎。
作为一个用例,请考虑我们要对数组中的每个值执行某些操作。
[1,2,3].map{|item| item+1} #=> takes each item in the array gets one added to it
不那么明显的是,这个函数返回一个数组[2,3,4]
,因为内部函数负责数据结构的迭代。这比使用另一个在数组上运行的函数和另一个在每个项目中添加一个的函数更方便和声明。
在csv示例中,您将获取每一行并将其添加到名为@books_in_stock
的数据结构中,但它不是明确的,我认为是我给出的示例。查看Enumearble类http://apidock.com/ruby/Enumerable,了解使用块的许多好例子。
答案 1 :(得分:1)
没有亲自使用Ruby的CSV类,但它看起来像是因为它被告知“headers:true”它假设第一行包含标题,并且每个后续行是与其上方的标题对应的数据。
答案 2 :(得分:0)
这是内置csv模块的一个功能,它带有ruby。创建CSV对象时,传入headers:true标志,告知csv对象名称或列以及存在的列数。之后,在cvs类上定义的foreach方法为表中的每一行设置别名行。然后用每行中的数据填充哈希行。
答案 3 :(得分:0)
好的,所以每当你使用do...end
或{...}
创建一个块时,你实际上是在创建一个匿名方法:
my_method do |arg1,arg2|
...
end
和
是一回事def ... arg1, arg2
...
end
关键是,您调用的方法(foreach
)可以随时调用do...end
块中的代码代码,并使用它选择的任何参数。对于foreach
方法,它将为它必须处理的每一行调用一次块,并且该行将在row
变量内(每次不同)可用,就像它是一个方法一样参数
修改强>
您的具体问题的答案在于传递到行中的变量的类型。它看起来像是一个CSV :: Row对象,它定义了一个方法row.[]
,它允许你获取在你传入的标题下面出现的那一行的值
答案 4 :(得分:0)
进入的行被视为散列,因此row["ISBN"]
正在调用第一次通过块设置的ISBN密钥,因为您将标头设置为true作为CSV foreach选项之一。所以ISBN的关键值是123. Ruby语法看起来像"isbn" => "123"
或key => value
在这种情况下,每个进入的行被视为一个单独的散列,其中键由标题行设置,值从csv行中的位置派生。