推送到不按预期工作的数组

时间:2012-11-18 04:51:38

标签: ruby

当我执行下面的代码时,我的数组'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"]]

我做错了什么?

4 个答案:

答案 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