在 Go 中使用 c 风格迭代器的惯用方式
idiomatic way to use c style iterator with Go
我是 Go 编程的新手(3-4 天),我正在尝试编写一些代码,使用现有的第三方 C 库使用 cgo 读取二进制文件。 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)
}
我认为您很少想要您链接到的博客 post 中更奇特的迭代器选项,即带有闭包或通道的迭代器选项。通道尤其会调用许多用于协调实际线程工作负载的机制,并且根据惯例,在 Go 中 for 循环看起来很典型,这取决于它们迭代的内容。 (在这方面,它类似于 C 中的迭代,但不同于(比如)Python、C++ 或 Java。)
我是 Go 编程的新手(3-4 天),我正在尝试编写一些代码,使用现有的第三方 C 库使用 cgo 读取二进制文件。 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)
}
我认为您很少想要您链接到的博客 post 中更奇特的迭代器选项,即带有闭包或通道的迭代器选项。通道尤其会调用许多用于协调实际线程工作负载的机制,并且根据惯例,在 Go 中 for 循环看起来很典型,这取决于它们迭代的内容。 (在这方面,它类似于 C 中的迭代,但不同于(比如)Python、C++ 或 Java。)