Golang – 在扇入中进行排序

huangapple go评论139阅读模式
英文:

Golang - Sorting on fan in

问题

我正在随机生成一堆日志消息,生成后,我需要按时间戳对它们进行排序,然后将它们写入日志。我正在利用sort库的sort.Interface特性,以便根据时间戳进行排序。我正在使用一个并发设计的扇入模式,所以我的排序函数会聚合所有来自goroutine的日志消息,然后对它们进行排序。

以下是我的代码:

  1. type CommonLogFormat struct {
  2. HostIP string
  3. UserIdent string
  4. User string
  5. Timestamp string
  6. Request string
  7. HttpStatusCode int
  8. Size int
  9. }
  10. type Logs struct {
  11. Messages []*CommonLogFormat
  12. }
  13. func sortByTimestamp(ch chan<- *CommonLogFormat) *Logs {
  14. logs := &Logs{Messages: make([]*CommonLogFormat, 0)}
  15. for i := range ch {
  16. logs.Messages = append(logs.Messages, i)
  17. }
  18. sort.Sort(logs)
  19. return logs
  20. }
  21. func (l Logs) Len() int {
  22. return len(l.Messages)
  23. }
  24. func (l Logs) Less(i, j int) bool {
  25. return l.Messages[i].Timestamp < l.Messages[j].Timestamp
  26. }
  27. func (l *Logs) Swap(i, j int) {
  28. l.Messages[i], l.Messages[j] = l.Messages[j], l.Messages[i]
  29. }

然而,当我尝试从通道接收日志消息时,我遇到了以下错误:

  1. invalid operation: <-i (receive from non-chan type *CommonLogFormat)

为什么我无法从通道接收值?

英文:

I am randomly generating a bunch of log messages, and after they have been generated, I need to sort them by timestamp before writing them to the logs. I'm utilising the sort.Interface aspect of the sort library so I can sort based on my timestamp. I'm using a fan-in concurrency design, so my sorting function aggregates all the log messages from the goroutines, then sorts them.

Here is my code:

  1. type CommonLogFormat struct {
  2. HostIP string
  3. UserIdent string
  4. User string
  5. Timestamp string
  6. Request string
  7. HttpStatusCode int
  8. Size int
  9. }
  10. type Logs struct {
  11. Messages []*CommonLogFormat
  12. }
  13. func sortByTimestamp(ch chan &lt;- *CommonLogFormat) *Logs {
  14. logs := &amp;Logs{Messages: make([]*CommonLogFormat, 1)}
  15. for i := range ch {
  16. logs.Messages = append(logs.Messages, &lt;- i)
  17. }
  18. sort.Sort(logs)
  19. return logs
  20. }
  21. func (l Logs) Len() int {
  22. return len(l.Messages)
  23. }
  24. func (l Logs) Less(i,j int) bool {
  25. return l.Messages[i].Timestamp &lt; l.Messages[j].Timestamp
  26. }
  27. func (l *Logs) Swap(i,j int) {
  28. l.Messages[i], l.Messages[j] = l.Messages[j], l.Messages[i]
  29. }

However, when I go to receive a log message from the channel, I get this error:

  1. invalid operation: &lt;-i (receive from non-chan type *CommonLogFormat)

Why can't I receive a value from the channel?

答案1

得分: 2

我认为错误信息已经很明显了。看看这段代码:

  1. for i := range ch {
  2. logs.Messages = append(logs.Messages, <-i)
  3. }

ch 的类型是 chan<- *CommonLogFormat,也就是一个通道。for range 循环遍历通道,将通道中发送的值存储在循环变量 i 中。i 不是一个通道,而是通道中发送的值,所以它的类型是 *CommonLogFormat

所以没有必要,也不能从中接收,因为它已经是你想要接收的值了。只需简单地将 i 追加到 logs.Messages 中:

  1. for i := range ch {
  2. logs.Messages = append(logs.Messages, i)
  3. }

规范:For 语句 中详细说明了在 for range 的情况下循环变量的含义:

  1. Range 表达式 第一个值 第二个值
  2. 数组或切片 a [n]E, *[n]E, or []E 索引 i int a[i] E
  3. 字符串 s string 类型 索引 i int 参见下文 rune
  4. 映射 m map[K]V k K m[k] V
  5. 通道 c chan E, <-chan E 元素 e E
  6. 最后一行适用于遍历通道的情况,第一个迭代值是元素。
  7. > 对于通道,产生的迭代值是在通道上发送的连续值,直到通道被关闭为止。如果通道为 `nil`,则 range 表达式将永远阻塞。
  8. [1]: https://golang.org/ref/spec#For_statements
  9. [2]: https://golang.org/ref/spec#Close
英文:

I think the error message is pretty self-explanatory. Look at this:

  1. for i := range ch {
  2. logs.Messages = append(logs.Messages, &lt;- i)
  3. }

ch is of type chan &lt;- *CommonLogFormat. ch is a channel. The for range loop over the channel yields the values sent on the channel, which will be stored in the loop variable i. i is not a channel, but the values sent on the channel, so it will be of type *CommonLogFormat.

So no need, and you actually can't receive from it, it is already what you would want to receive from it. Simply append i:

  1. for i := range ch {
  2. logs.Messages = append(logs.Messages, i)
  3. }

The Spec: For statements details what the loop variables are in case of for range:

  1. Range expression 1st value 2nd value
  2. array or slice a [n]E, *[n]E, or []E index i int a[i] E
  3. string s string type index i int see below rune
  4. map m map[K]V key k K m[k] V
  5. channel c chan E, &lt;-chan E element e E

The last line applies in case of ranging over a channel, and the first iteration value is the element.

> For channels, the iteration values produced are the successive values sent on the channel until the channel is closed. If the channel is nil, the range expression blocks forever.

huangapple
  • 本文由 发表于 2016年12月5日 04:05:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/40963042.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定