英文:
Golang: Can I cast to chan interface{}
问题
我正在尝试编写一个通用的订阅包装器,类似于:
type Subscriber interface {
    Subscribe(addr string) chan interface{}
}
假设我想要使用一个库,该库中有一个subscribe方法,但它使用了chan library.Object。我想要做的是:
func (s *mySubscriber) Subscribe(addr string) chan interface{} {
    ch := make(chan library.Object)
    library.Subscribe(addr, ch)
    return chan interface{}(ch)
}
目前,我不认为这样的类型转换是可能的。而且我不想修改底层库,因为包装器应该对库的实现是不可知的。
我看到过类似的问题:https://stackoverflow.com/questions/13425490/is-there-a-way-to-cast-structs-for-sending-over-a-channel,但在那种情况下,可以修改应用程序以满足需求。在这里,无法修改。这种转换是否可能?是否有更好的方法?
一种解决方案是将一个通用的通道传递给Subscribe,并在chan library.Object上无限期等待,并将接收到的任何内容发送到我的通用通道,但我不太喜欢为了绕过类型转换而引入另一个通道。
英文:
I am trying to write a general purpose wrapper for subscriptions, something like:
type Subscriber interface{
    Subscribe(addr string) chan interface{}
}
Suppose there is a library I want to use which has a subscribe method in it, but which uses a chan library.Object. I would like to be able to do something like:
func (s *mySubscriber) Subscribe(addr string) chan interface{}{
    ch := make(chan library.Object)
    library.Subscribe(addr, ch)
    return chan interface{}(ch)
}
Currently, I don't believe such a cast is possible. And I don't want to modify the underlying library, since the wrapper should be agnostic to library implementations.
I've seen https://stackoverflow.com/questions/13425490/is-there-a-way-to-cast-structs-for-sending-over-a-channel, but in that case the application can be modified to suit the need. Here, it can't. Is this possible? Is there a better way?
One solution is to pass in a general purpose channel into Subscribe, and to wait indefinetely on chan library.Object and fire anything that comes through on my general channel, but I didn't particularly like having to introduce another channel just to get around the type cast.
答案1
得分: 7
不,你不能只用一个转换来实现这个。你必须使用一个额外的通道,就像你已经考虑到的那样。幸运的是,已经有一个辅助库可以做到这一点(免责声明:我写过它)。你需要使用Wrap函数。
- 文档:https://godoc.org/github.com/eapache/channels#Wrap
 - 代码:https://github.com/eapache/channels/
 
英文:
No, you can't do this with just a cast. You have to use an extra channel, as you have already considered. Fortunately, there is a helper library for this already (disclaimer: I wrote it). You want the Wrap function.
- Documentation: https://godoc.org/github.com/eapache/channels#Wrap
 - Code: https://github.com/eapache/channels/
 
答案2
得分: 2
对于其他遇到此问题并希望使用内联代码的人:
// 将超时通道包装在通用接口通道中
func makeDefaultTimeoutChan() <-chan interface{} {
  channel := make(chan interface{})
  go func() {
    <-time.After(30 * time.Second)
    channel <- struct{}{}
  }()
  return channel
}
// 使用示例
func main() {
  resultChannel := doOtherThingReturningAsync()
  cancel := makeDefaultTimeoutChan()
  select {
    case <-cancel:
      fmt.Println("已取消!")
    case results := <-resultChannel:
      fmt.Printf("得到结果:%#v\n", results)
  }
}
希望这对你有帮助!
英文:
For anyone else that stumbles on this issue and wants some inline code:
// wrap a timeout channel in a generic interface channel
func makeDefaultTimeoutChan() <-chan interface{} {
  channel := make(chan interface{})
  go func() {
    <-time.After(30 * time.Second)
    channel <- struct{}{}
  }()
  return channel
}
// usage
func main() {
  resultChannel := doOtherThingReturningAsync()
  cancel := makeDefaultTimeoutChan()
  select {
    case <-cancel:
      fmt.Println("cancelled!")
    case results := <-resultChannel:
      fmt.Printf("got result: %#v\n", results)
  }
}
答案3
得分: 0
我可以使用Go泛型来完成这个任务:
func Wrap[T any](from chan T) chan interface{} {
    to := make(chan interface{})
    go func() {
        var val T
        for {
            val = <-from
            to <- val
        }
    }()
    return to
}
func Unwrap[T any](from chan interface{}) chan T {
    to := make(chan T)
    go func() {
        var val interface{}
        for {
            val = <-from
            to <- val.(T)
        }
    }()
    return to
}
这段代码使用了Go的泛型功能,通过Wrap函数将一个类型为T的通道转换为一个类型为interface{}的通道,而Unwrap函数则将一个类型为interface{}的通道转换为一个类型为T的通道。
英文:
I was able to do this with Go generics:
func Wrap[T any](from chan T) chan any {
  to := make(chan any)
  go func() {
	var val T
	for {
	  val = <-from
	  to <- val
	}
  }()
  return to
}
func Unwrap[T any](from chan any) chan T {
  to := make(chan T)
  go func() {
	var val any
	for {
		val = <-from
		to <- val.(T)
	}
  }()
  return to
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论