2012-10-15 75 views
6
type Friend struct { 
    name string 
    age int 
} 

type Friends struct { 
    friends []Friend 
} 

我想打Friends范围,能,这意味着,如果我有一个变量my_friendsFriends类型,我可以循环使用虽:使结构“范围”?

for i, friend := range my_friends { 
    // bla bla 
} 

是可以进去吗?

+2

你能说出一个真实世界的用例吗?即,为什么你想要这个,而不是'范围Friends.friends'或'范围Friends.List()'(仅限示例)? –

+0

示例:稍后将列表升级到家庭列表(朋友组),并且您不希望更改现有的客户端代码,这些代码完全适用于单个朋友。 – Stein

回答

-1

例如,

var my_friends Friends 

for i, friend := range my_friends.friends { 
    // bla bla 
} 
+1

这不是真正的原始问题的答案。 – simonmenke

+1

@simonmenke是的,但它可以更清楚地表明OP不需要什么。 –

9

当心:作为deft_code提到,此代码泄漏的信道和一个的goroutine当循环中断。不要将其用作一般模式。


在走,没有办法作出range兼容任意类型, range只支持切片,数组,渠道和地图。

您可以使用range来迭代通道,如果您想迭代动态生成的数据而无需使用片或数组,那么这非常有用。

例如:

func Iter() chan *Friend { 
    c := make(chan *Friend) 
    go func() { 
     for i:=0; i < 10; i++ { 
     c <- newFriend() 
     } 
     close(c) 
    }() 
    return c 
} 

func main() { 
    // Iterate 
    for friend := range Iter() { 
    fmt.Println("A friend:", friend) 
    } 
} 

这就是你可以做一些 'rangeable' 最接近。

因此,通常的做法是在您的类型上定义方法Iter()或类似的东西, 将其传递给range

请参阅the spec以进一步阅读range

+2

当然不利的一面是,与跨越切片相比,在这里使用频道效率不高。每个通道的读/写都可能导致运行时切换到不同的goroutine,在大多数情况下,您可以在一个切片上进行切片而不会被其他goroutine抢占。 –

+1

这是真实的,直到构造切片是昂贵的或其他不合需要的。例如,在[cbfs](https://github.com/couchbaselabs/cbfs)中,我有时会遍历所有文件(或范围内的文件)。可能有数十亿个,它需要对数据库的批量请求和有趣的东西。 – Dustin

+2

如果范围没有迭代到完成,这会泄漏通道和goroutine。泄漏的简单解决方案导致比赛或死锁。完整的强大解决方案非常复杂和微妙。 Google内部Go邮件列表的共识是这是一个反模式。 –

11

好友要成为一个结构?否则简单地做

type Friends []Friend 
+2

我认为这是一个非常好的答案。如果“朋友结构”只包含显示的内容,则将该类型定义为“类型Friends []朋友”。 Go可以使用这种类型的方法,而不仅仅是'struct's,它与大多数语言有点不同。 –

+0

这是一个很好的答案,只要你不需要一个结构... –