当我执行下面的代码时,我的数组'tasks'最终会从数据库中每行重复的dbi调用的最后一行开始。
require 'dbi'
require 'PP'
dbh = DBI.connect('DBI:SQLite3:test', 'test', '')
dbh.do("DROP TABLE IF EXISTS TASK;")
dbh.do("CREATE TABLE TASK(ID INT, NAME VARCHAR(20))")
# Insert two rows
1.upto(2) do |i|
sql = "INSERT INTO TASK (ID, NAME) VALUES (?, ?)"
dbh.do(sql, i, "Task #{i}")
end
sth = dbh.prepare('select * from TASK')
sth.execute
tasks = Array.new
while row=sth.fetch do
p row
p row.object_id
tasks.push(row)
end
pp(tasks)
sth.finish
因此,如果我的TASK表中有两行,那么不要在tasks数组中获取它:
[[1, "Task 1"], [2, "Task 2"]]
我明白了
[[2, "Task 2"], [2, "Task 2"]]
完整输出如下所示:
[1, "Task 1"]
19877028
[2, "Task 2"]
19876728
[[2, "Task 2"], [2, "Task 2"]]
我做错了什么?
答案 0 :(得分:2)
似乎行对象中有一些奇怪的行为,似乎是某种单例,这就是为什么dup方法不会解决它。
跳转到源代码似乎to_a方法将复制内部行元素,这就是它工作的原因所以答案是在行对象上使用to_a,或者如果你想要你也可以将它转换为Hash来保存元。
while row=sth.fetch do
tasks.push(row.to_a)
end
但我推荐更多红宝石
sth.fetch do |row|
tasks << row.to_a
end
答案 1 :(得分:1)
您确定已将您的代码完全复制吗? AFAIK你编写的代码根本不应该工作...... 你混合了两个不打算用这种方式构造的结构。
假设您来自C或Java背景,我错了吗?红宝石中的迭代是非常不同的,让我试着解释一下。
ruby中的while循环具有以下结构:
while condition
# code to be executed as long as condition is true
end
带有块的方法具有以下结构:
sth.fetch do |element|
# code to be executed once per element in the sth collection
end
现在有一些非常重要的事情要理解:fetch
,或者ruby中的任何其他类型的方法,不是你在C中遇到的迭代器 - 你没有必须再次将它再次称为 ,直到迭代器到达集合的末尾。
您只需将其称为一次,并将其作为参数提供块,这是一种匿名函数(如javascript中所示)。然后fetch
方法会将(&#34; yield&#34;)集合中的每个元素一个接一个地传递到此块。
因此,您的案例中的正确语法应为:
sth.fetch do |row|
p row
tasks.push row
end
这可能是这样写的,在一所更老的学校里#34;时尚:
# define a function
# = this is your block
def process( row )
p row
tasks.push row
end
# pass each element of a collection to this function
# = this is done inside the fetch method
for row in sth
process row
end
我建议你阅读更多关于块/ procs / lambdas的内容,因为它们遍布红宝石,而恕我直言是这种语言非常棒的原因之一。迭代器只是一个开始,你可以用这些来做更多...如果你需要好的参考文档,pickaxe被认为是rubyists中最好的资源之一,如果你愿意,我可以告诉你更多。
答案 2 :(得分:0)
我不知道您的代码是如何完全运行的,但我想如果您将tasks.push(row)
更改为tasks.push(row.dup)
,那么它将起作用。如果是这种情况,那么sth.fetch
每次都会继续为您提供相同的数组(相同的对象ID),即使其内容已更新,并且您将相同的数组反复推送到tasks
。
答案 3 :(得分:0)
有很多事情可以发生,但试试这个。
首先使用parens确保块传递到while。
while (row=sth.fetch) do
p row
tasks.push(row)
end
然后是惯用的红宝石方式
sth.fetch do |row|
p row
tasks << row # same as push
end