转到通用渠道类型
Go Generic Channel Type
我目前正在尝试通过通道将数据发送到 goroutine,然后 goroutine 将进一步处理它。我的问题是我希望频道能够处理任何类型。为此,我正在研究 Go 1.18 中新引入的泛型。
我的问题是我需要在启动 goroutine 时告诉它通道的类型,这是不可能告诉的,因为它可以保存任何数据。
这是我现在得到的:
话题:
func StartController[T any](sender chan Packet[T]) {
go runThread(sender)
}
func runThread[T any](sender chan Packet[T]) {
fmt.Println("in thread")
for true {
data := <- sender
fmt.Println(data)
}
}
我的测试函数是这样的:
func main() {
sender := make(chan Packet)
StartController(sender)
sender <- Packet[int]{
Msg: Message[int]{
Data: 1,
},
}
sender <- Packet[string]{
Msg: Message[string]{
Data: "asd",
},
}
for true {}
}
类型:
type Message[T any] struct {
Data T
}
type Packet[T any] struct {
Msg Message[T]
}
现在这段代码无法编译,因为
.\test.go:8:22: cannot use generic type Packet[T interface{}] without instantiation
有没有办法正确地做到这一点?
我正在研究不使用泛型而只使用 interface{} 作为类型,但这会使整个逻辑变得混乱,因为它需要解析(甚至可能不可能,因为数据可能相当复杂(嵌套结构))
这是一种错误的泛型使用方式。
参数化类型,如 chan T
,必须先使用具体类型参数实例化,然后才能使用它。给定一个定义的 chan 类型:
type GenericChan[T any] chan T
您仍然需要使用具体类型实例化它:
c := make(GenericChan[int])
这使得使用类型参数有点没有实际意义。
我不知道你的背景是什么,但考虑一下长期以来泛型一直稳定存在的语言。例如。 Java。并考虑典型的 Java 通用收集器 List<T>
。你通常做的是用一个类型实例化它:
var list = new ArrayList<String>();
您在这里试图做的是声明一个可以采用任何类型的通道。在 Java 中,可以包含任何类型的列表是什么?
var list = new ArrayList<Object>();
在 Go 中,这就是
c := make(chan interface{})
您可以换个角度看:您如何期望这个通用的 chan 在 receive 操作上工作?
c := make(GenericChan) // wrong syntax: instantiating without type param
c <- "a string" // let's pretend you can send anything into it
// ...
foo := <-c
此时foo
是什么?是 string
吗?还是 int
?你可以发送任何东西进去。这就是为什么像您的示例中的通用 chan 无法按您预期的方式工作的原因。它必须是 chan interface{}
然后你像现在没有泛型一样对收到的项目进行类型断言。
泛型的重点是编写使用任意类型的代码,同时保持类型安全:
func receiveAny[T any](c chan T) T {
return <-c
}
您可以使用 chan int
或 chan string
调用。
我目前正在尝试通过通道将数据发送到 goroutine,然后 goroutine 将进一步处理它。我的问题是我希望频道能够处理任何类型。为此,我正在研究 Go 1.18 中新引入的泛型。
我的问题是我需要在启动 goroutine 时告诉它通道的类型,这是不可能告诉的,因为它可以保存任何数据。
这是我现在得到的:
话题:
func StartController[T any](sender chan Packet[T]) {
go runThread(sender)
}
func runThread[T any](sender chan Packet[T]) {
fmt.Println("in thread")
for true {
data := <- sender
fmt.Println(data)
}
}
我的测试函数是这样的:
func main() {
sender := make(chan Packet)
StartController(sender)
sender <- Packet[int]{
Msg: Message[int]{
Data: 1,
},
}
sender <- Packet[string]{
Msg: Message[string]{
Data: "asd",
},
}
for true {}
}
类型:
type Message[T any] struct {
Data T
}
type Packet[T any] struct {
Msg Message[T]
}
现在这段代码无法编译,因为
.\test.go:8:22: cannot use generic type Packet[T interface{}] without instantiation
有没有办法正确地做到这一点?
我正在研究不使用泛型而只使用 interface{} 作为类型,但这会使整个逻辑变得混乱,因为它需要解析(甚至可能不可能,因为数据可能相当复杂(嵌套结构))
这是一种错误的泛型使用方式。
参数化类型,如 chan T
,必须先使用具体类型参数实例化,然后才能使用它。给定一个定义的 chan 类型:
type GenericChan[T any] chan T
您仍然需要使用具体类型实例化它:
c := make(GenericChan[int])
这使得使用类型参数有点没有实际意义。
我不知道你的背景是什么,但考虑一下长期以来泛型一直稳定存在的语言。例如。 Java。并考虑典型的 Java 通用收集器 List<T>
。你通常做的是用一个类型实例化它:
var list = new ArrayList<String>();
您在这里试图做的是声明一个可以采用任何类型的通道。在 Java 中,可以包含任何类型的列表是什么?
var list = new ArrayList<Object>();
在 Go 中,这就是
c := make(chan interface{})
您可以换个角度看:您如何期望这个通用的 chan 在 receive 操作上工作?
c := make(GenericChan) // wrong syntax: instantiating without type param
c <- "a string" // let's pretend you can send anything into it
// ...
foo := <-c
此时foo
是什么?是 string
吗?还是 int
?你可以发送任何东西进去。这就是为什么像您的示例中的通用 chan 无法按您预期的方式工作的原因。它必须是 chan interface{}
然后你像现在没有泛型一样对收到的项目进行类型断言。
泛型的重点是编写使用任意类型的代码,同时保持类型安全:
func receiveAny[T any](c chan T) T {
return <-c
}
您可以使用 chan int
或 chan string
调用。