How to define a type constraint for any channel type

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

How to define a type constraint for any channel type

问题

我正在尝试定义一个函数,该函数返回给定通道使用率的百分比:

func ChannelUsagePct[T any](channel chan T) int {
	channelCap := cap(channel)
	channelLen := len(channel)
	if channelCap == 0 {
		// 无缓冲通道
		return 0
	}
	return 100 * channelLen / channelCap
}

func main() {
	twoWayChannel := make(chan int, 10)
	var sendOnlyChannel chan<- int = twoWayChannel
	var recvOnlyChannel <-chan int = twoWayChannel

	fmt.Println(ChannelUsagePct(twoWayChannel))
	fmt.Println(ChannelUsagePct(sendOnlyChannel)) // 不起作用
	fmt.Println(ChannelUsagePct(recvOnlyChannel))  // 不起作用
}

现在的问题是,这个函数对于第一个通道有效,但对于第二个和第三个通道无效,而不改变函数的签名。但是,如果我改变签名,我需要选择通道是只接收还是只发送。有没有一种定义零通道的方法?例如,不能读取也不能写入,我只想在其上使用caplen函数。
理想情况下,ChannelUsagePct应该适用于这三种情况中的任何一种。

英文:

I'm trying to define a funcion that returns the percentage of usage of a given channel:

func ChannelUsagePct[T any](channel chan T) int {
	channelCap := cap(channel)
	channelLen := len(channel)
	if channelCap == 0 {
		// Unbuffered channel
		return 0
	}
	return 100 * channelLen / channelCap
}

func main() {
	twoWayChannel := make(chan int, 10)
	var sendOnlyChannel chan&lt;- int = twoWayChannel
	var recvOnlyChannel &lt;-chan int = twoWayChannel

	fmt.Println(ChannelUsagePct(twoWayChannel))
	fmt.Println(ChannelUsagePct(sendOnlyChannel)) // Does not work 
	fmt.Println(ChannelUsagePct(recvOnlyChannel))  // Does not work 
}

Now the thing is that this works for the first channel but not for the second and third, without changing the func's signature. But if I change the signature, I need to either choose the channel to be receive only, or send only. Is there a way to define a channel that is zero-way? E.g. cannot be read nor written to, I just want to use cap and len funcs on it.
Ideally the ChannelUsagePct should work for any of the 3 cases.

答案1

得分: 3

为了允许通道的三种可能形式,需要定义一个单独的类型约束。

type Chan[T any] interface {
	chan T | <-chan T | chan<- T
}

当使用时,需要使用类型参数将类型约束实例化为T的类型:

func Cap[T any, C Chan[T]](c C) int {
	return cap(c)
}

由于实例化的存在,无法推断整个类型,只需要提供通道元素类型:

ch := make(chan int, 3)
i := Cap[int](ch)
fmt.Println(i)
// 3

https://go.dev/play/p/1lx5R4MFvFx

英文:

In order to allow all three possible forms of a channel, a separate type constraint needs to be defined.

type Chan[T any] interface {
	chan T | &lt;-chan T | chan&lt;- T
}

This will require instantiating the type constraint with the type of T when it's used, which can be done with another type parameter:

func Cap[T any, C Chan[T]](c C) int {
	return cap(c)
}

Because of that instantiation the entire type cannot be inferred, but only the channel element type needs to be supplied:

ch := make(chan int, 3)
i := Cap[int](ch)
fmt.Println(i)
// 3

https://go.dev/play/p/1lx5R4MFvFx

huangapple
  • 本文由 发表于 2023年7月1日 00:31:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/76590753.html
匿名

发表评论

匿名网友

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

确定