【问题标题】:Go Generic Channel Type去通用频道类型
【发布时间】:2021-11-27 18:47:06
【问题描述】:

我目前正在尝试通过通道将数据发送到 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{} 作为类型,但这会使整个逻辑变得混乱,因为它需要解析(甚至可能不可能,因为数据可能相当复杂(嵌套结构) )

【问题讨论】:

    标签: go generics beta


    【解决方案1】:

    这是使用泛型的错误方式。

    参数化类型,如chan T,必须先用具体的类型参数进行实例化,然后才能使用它。给定 cmets 中建议的已定义 chan 类型:

    type GenericChan[T any] chan T
    

    您仍然需要使用具体类型对其进行实例化:

    c := make(GenericChan[int])
    

    这使得使用类型参数有点没有意义。

    我不知道您的背景是什么,但请考虑一下泛型长期以来一直稳定存在的语言。例如。爪哇。并考虑典型的 Java 通用收集器List&lt;T&gt;。你通常做的是用一个类型实例化它:

    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 intchan string 拨打电话。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-06
      • 1970-01-01
      • 2014-12-29
      • 2018-11-09
      • 2011-08-24
      • 2015-12-15
      • 1970-01-01
      相关资源
      最近更新 更多