使用Go的c风格迭代器的惯用方法

时间:2015-09-25 00:02:14

标签: go iterator cgo

我是Go编程的新手(3-4天),我正在尝试使用cgo编写一些使用现有第三方C库读取二进制文件的代码。 C库的这种做法似乎相当标准(对于C)。稍微简化它看起来像:

int main(int argc, char *argv[]) {
    file_t *file = file_open(filename);
    index_t *index = index_load(file, filename);
    iterator_t *iter = query(idx, header, region);
    record_t *record = record_init();

    while (iterator_next(file, iter, record) >= 0) {
        /* Do stuff with record */
    }

    iterator_destroy(iter);
    record_destroy(record);
    file_close(file);

    return 0;
}

我写了以下Go代码:

func main() {
    file := Open(filename)
    record := NewRecord()
    iter := file.Query(region)
    for {
        n, err := file.Next(iter, record)
        if err != nil {
            log.Fatal(err)
        }
        if n <= 0 {
            // No more records to read.
            break
        }
    }
}

这是有效的,因为它允许我访问特定查询区域中的记录。

我的问题是,这是否是在Go中处理此任务的惯用方法,还是有更好的替代方案?我已经看过像http://ewencp.org/blog/golang-iterators这样的网站,但似乎无法让这些例子与C库一起工作(我想这可能是因为C库在每次迭代时重用了record_t变量而不是创建一个新变量,但也许只是我缺乏Go的经验。

1 个答案:

答案 0 :(得分:0)

您所做的与使用io.Reader移动文件不同:

err, n := error(nil), 0
for err == nil {
    err, n = f.Read(in)
    // ...do stuff with in[:n]...
}

或使用(*bufio.Scanner).Scan()(请参阅the docs):

for scanner.Scan() {
    // ...do something with scanner.Text()...
}
if err := scanner.Err(); err != nil {
    log.Fatalln(err)
}

我认为你很少想要链接到的博客文章中更具异国情调的迭代器选项,包括闭包或频道。特别是通道调用了许多用于协调实际线程工作负载的机器,并且就常规而言,Go for循环中的典型特征是根据它们重复的内容而略有不同。 (在这方面,它类似于C中的迭代,但与(例如)Python,C ++或Java不同。)