可以将chan interface{}转换为其他类型吗?

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

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.

答案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() &lt;-chan interface{} {
  channel := make(chan interface{})
  go func() {
    &lt;-time.After(30 * time.Second)
    channel &lt;- struct{}{}
  }()
  return channel
}

// usage
func main() {
  resultChannel := doOtherThingReturningAsync()
  cancel := makeDefaultTimeoutChan()
  select {
    case &lt;-cancel:
      fmt.Println(&quot;cancelled!&quot;)
    case results := &lt;-resultChannel:
      fmt.Printf(&quot;got result: %#v\n&quot;, 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 = &lt;-from
	  to &lt;- val
	}
  }()
  return to
}

func Unwrap[T any](from chan any) chan T {
  to := make(chan T)
  go func() {
	var val any
	for {
		val = &lt;-from
		to &lt;- val.(T)
	}
  }()
  return to
}

huangapple
  • 本文由 发表于 2014年8月31日 23:19:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/25593367.html
匿名

发表评论

匿名网友

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

确定