英文:
idiomatic way to use c style iterator with Go
问题
我非常新于Go编程(3-4天),我正在尝试使用现有的第三方C库(使用cgo)编写一些读取二进制文件的代码。这个C库的做法似乎相当标准(对于C来说)。稍微简化一下,代码如下:
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的经验不足)。
英文:
I'm very new to Go programming (3-4 days), and I'm trying to write some code that reads a binary file using an existing third-party C library using cgo. The C library's way of doing this seems fairly standard (for C). Slightly simplified it looks like:
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;
}
I have written the following Go code:
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
}
}
}
This works, in the sense that it will allow me to access the records in a particular query region.
My question is whether this is an idiomatic way to approach this task in Go, or are there better alternatives? I've seen sites such as http://ewencp.org/blog/golang-iterators, but seem unable to get these examples to work with the C library (I was thinking it may be because the C library is reusing the record_t variable on each iteration rather than creating a new variable, but maybe it's just my lack of experience with Go).
答案1
得分: 0
你正在做的事情与使用io.Reader
在文件中移动并没有太大的区别:
err, n := error(nil), 0
for err == nil {
err, n = f.Read(in)
// ...使用in[:n]做一些操作...
}
或者使用(*bufio.Scanner).Scan()
(参见文档):
for scanner.Scan() {
// ...对scanner.Text()做一些操作...
}
if err := scanner.Err(); err != nil {
log.Fatalln(err)
}
我认为你很少需要博文中提到的更奇特的迭代选项,比如使用闭包或通道。特别是通道会调用很多用于协调真实线程工作负载的机制,在惯例上,根据迭代的内容,Go语言中的循环看起来可能会有所不同。(在这方面,它类似于C语言,但与Python、C++或Java不同。)
英文:
What you're doing isn't that different from moving through a file with an io.Reader
:
err, n := error(nil), 0
for err == nil {
err, n = f.Read(in)
// ...do stuff with in[:n]...
}
Or using (*bufio.Scanner).Scan()
(see the docs):
for scanner.Scan() {
// ...do something with scanner.Text()...
}
if err := scanner.Err(); err != nil {
log.Fatalln(err)
}
I think you rarely want the more exotic iterator options in the blog post you linked to, the ones with closures or channels. Channels in particular invoke a lot of machinery meant for coordinating real threaded workloads, and in terms of convention, it's just typical in Go for loops to look a little different depending on what they're iterating. (In that respect, it's like iteration in C, but different from (say) Python, C++, or Java.)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论