go - 在 Go 中使用 c 风格迭代器的惯用方式

标签 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 的经验).

最佳答案

您所做的与使用 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)
}

我认为您很少想要链接到的博客文章中的更奇特的迭代器选项,即带有闭包或 channel 的迭代器选项。 channel 尤其会调用许多用于协调实际线程工作负载的机制,并且根据惯例,在 Go 中 for 循环看起来很典型,这取决于它们迭代的内容。 (在这方面,它类似于 C 中的迭代,但不同于(比如说)Python、C++ 或 Java。)

关于go - 在 Go 中使用 c 风格迭代器的惯用方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32772798/

相关文章:

mongodb - 使用 mgo 的 Golang 和 MongoDB 的全文搜索实现

go - 使用golang的goroutine如何实现计数器?

python - 可迭代列表的迭代类型转换

go - 如何在 Go 中包含来自第三方包的 header ?

macos - Golang下载和 '$GOPATH not set'

go - 如何区分哪些依赖项是可下载的?

c++ - 在 C++ 11 中迭代 STL 类

java - LRU缓存: linkedhashmap and iterator implementation not working

go - 使用 go build CGO_ENABLED 进行交叉编译 - 找不到警告 : libudev. so.1

cgo 结果有 go 指针