Golang中学习通道(Channel)及阅读官方文档的心得

Golang中学习通道(Channel)及阅读官方文档的心得 文档:

通道类型

可选的 <- 操作符指定通道的方向,发送或接收。如果没有指定方向,通道是双向的。通道可以通过赋值或显式转换被限制为仅发送或仅接收。

chan T          // 可用于发送和接收类型为 T 的值
chan<- float64  // 只能用于发送 float64 值
<-chan int      // 只能用于接收 int 值
<- 操作符尽可能与最左边的 chan 结合:

chan<- chan int    // 等同于 chan<- (chan int)
chan<- <-chan int  // 等同于 chan<- (<-chan int)
<-chan <-chan int  // 等同于 <-chan (<-chan int)
chan (<-chan int)

在 Rob Pike 的代码中:

<- 操作符尽可能与最左边的 chan 结合(文档)

为什么我们使用 c <- <- input1 来接收?c 是在发送 c <- 并接收 <-input1 吗?

chan<- (<-chan int)c <- (<- input1) 是等价的,但当我从左到右大声读出来时,这说不通。c 是在发送 c <- 并接收 <-input1 吗?<- <- 会相互抵消并默认最左边的通道接收吗?

我理解 c 是一个双向通道,因此它可以处理接收和发送的转换,但由于某种原因,我很难看出这里的逻辑模式。


更多关于Golang中学习通道(Channel)及阅读官方文档的心得的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

c <- <- input1input1 读取一个值并将其写入 c。更清晰的写法是:

  value := <-input
  c <- value

更多关于Golang中学习通道(Channel)及阅读官方文档的心得的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


c <- <- input1input1 读取一个值并将其写入 c。更清晰的写法是:

  value := <-input
  c <- value

谢谢 Jeff,非常感谢您的快速回复!

在通道操作中,c <- <-input1 的语法确实需要仔细理解。这里的关键是区分通道类型声明中的 <- 和通道操作中的 <-

通道操作解析:

c <- <-input1

实际上等价于:

c <- (<-input1)

这意味着:

  1. 先执行 <-input1input1 通道接收一个值
  2. 然后将这个值发送到通道 c

示例代码:

package main

import (
	"fmt"
	"time"
)

func main() {
	// 创建两个通道
	input1 := make(chan int)
	c := make(chan int)

	// 启动发送协程
	go func() {
		defer close(input1)
		for i := 1; i <= 3; i++ {
			input1 <- i
			time.Sleep(100 * time.Millisecond)
		}
	}()

	// 启动处理协程
	go func() {
		for {
			// 这里就是 c <- <-input1 的用法
			// 先从 input1 接收,然后发送到 c
			value, ok := <-input1
			if !ok {
				close(c)
				return
			}
			c <- value
		}
	}()

	// 主协程从 c 接收并打印
	for v := range c {
		fmt.Println("Received:", v)
	}
}

通道方向类型示例:

package main

import "fmt"

// 仅发送通道参数
func sendOnly(ch chan<- int, value int) {
	ch <- value
	// 以下代码会编译错误:不能从只发送通道接收
	// v := <-ch
}

// 仅接收通道参数
func receiveOnly(ch <-chan int) int {
	return <-ch
}

func main() {
	ch := make(chan int, 1)
	
	// 传递双向通道给只发送函数
	sendOnly(ch, 42)
	
	// 传递双向通道给只接收函数
	result := receiveOnly(ch)
	fmt.Println("Result:", result) // 输出: Result: 42
	
	// 类型转换示例
	var sendCh chan<- int = ch
	var recvCh <-chan int = ch
	
	sendCh <- 100
	value := <-recvCh
	fmt.Println("Value:", value) // 输出: Value: 100
}

复杂通道类型解析:

package main

import "fmt"

func process(ch <-chan <-chan int) {
	// ch 是接收通道,其元素类型是 <-chan int(只接收通道)
	for innerCh := range ch {
		// innerCh 是 <-chan int
		for v := range innerCh {
			fmt.Println("Value:", v)
		}
	}
}

func main() {
	// 创建通道的通道
	ch := make(chan (<-chan int))
	
	go func() {
		defer close(ch)
		
		// 创建内层通道
		inner1 := make(chan int, 2)
		inner1 <- 1
		inner1 <- 2
		close(inner1)
		ch <- inner1
		
		inner2 := make(chan int, 2)
		inner2 <- 3
		inner2 <- 4
		close(inner2)
		ch <- inner2
	}()
	
	process(ch)
}

c <- <-input1 中,第一个 <- 是发送操作符(紧挨着 c),第二个 <- 是接收操作符(紧挨着 input1)。Go 编译器会根据上下文正确解析这些操作符,不会出现 <- <- 相互抵消的情况。

回到顶部