我的程序有一个管道结构,我刚刚实现了一个缓存过滤器,如果已处理的数据版本在缓存中,它会直接将内容发送到输出。
func Run(in chan downloader.ReadyDownload) chan CCFile {
out := make(chan CCFile)
processQueue := make(chan downloader.ReadyDownload)
go cache.BypassFilter(in, processQueue, out)
// writes the cached, already processed version to out if it exists
// otherwise redirects the input to processQueue
go process(processQueue, out)
return out
}
问题是我的程序有多个这样的地方,并且许多类型的结构(如此片段中的ReadyDownload和CCFile)正在通过通道传递。它们都实现了这个接口
type ProcessItem interface {
Source() string
Target() string
Key() string
}
所以我的BypassFilter()函数签名如下所示:
func (c Cache) BypassFilter(in chan ProcessItem, process chan ProcessItem, bypass chan ProcessItem)
但是这会导致以下错误:
cannot use in (type chan downloader.ReadyDownload) as type chan utils.ProcessItem in function argument
虽然ReadyDownload肯定会实现ProcessItem。例如,这没有问题:
foo := downloader.ReadyDownload{}
var bar utils.ProcessItem
bar = foo
所以,我对Go类型和界面的理解非常有限,这让我想问这个问题:它们是的某些东西和其他东西,这使得这些类型不兼容?我该怎么做才能让它发挥作用?假设我有一个ReadyDownloads频道。是将数据转发到一个函数的唯一方法,即接口{}的通道作为参数,创建接口{}的新通道,将其传递给函数并从ReadyDownloads的通道读取内容并将它们送到另一个频道?
答案 0 :(得分:3)
这两种是不同的类型:
processQueue chan ReadyDownload
process chan ProcessItem
您可以在ReadyDownloader
类型的通道中放置chan ProcessItem
值(如果它实现了接口),但您无法将一种通道类型转换为另一种通道类型,就像您无法转换为[]T
切片成[]interface{}
切片,这是另一种类似于此的混淆。
您需要做的是制作chan ProcessItem
类型的所有渠道:
func Run(in chan ProcessItem) chan CCFile {
out := make(chan CCFile)
processQueue := make(chan ProcessItem)
go cache.BypassFilter(in, processQueue, out)
// writes the cached, already processed version to out if it exists
// otherwise redirects the input to processQueue
go process(processQueue, out)
return out
}
要详细了解这是为什么(对于切片,但同样适用于通道),您可以阅读以下go-wiki页面:
答案 1 :(得分:0)
将每个频道更改为struct
个频道可能会在此处有效,但一般情况下,您可能希望将struct
类型视为接口以便进行处理。幸运的是,go给了我们很多解决方案。这是一个。
考虑这个非常简单的设置,我们希望将Object
结构类型用作多个接口:
// Get the objects
func ParseFile(fileName string, co chan Object) {
for _, object := range DoStuff(fileName) {
co <- object
}
}
// Use some saving functionality that is defined elsewhere as:
func Archive(cs chan Saveable) {
for saveable := range cs {
saveable.Save()
}
}
type Saveable interface {
Save()
}
//Implement the interfaces...
func (*Object) Save() {
fmt.Println("Naa, I'm lazy")
}
// Or some throwing functionality?
func ThrowOnTheWall(ct chan Throwable) {
for throwable := range cs {
throwable.Throw()
}
}
//...
co := make(chan Object)
go ParseFile("file.xml", co)
Archive(co) // Will NOT work, co is of the wrong type.
在这里,使用某些地方chan Object
是不合适的,因为你可能想要在墙上扔一些与对象不同的东西(例如type Defecation struct {...}
,你将它作为Throwable
来实现太)。
您可以使用go例程在后台进行投射:
func ObjectToSaveable(from chan Object) chan Saveable {
to := make(chan Saveable)
go func() {
for object := range from {
to <- &object
}
close(to)
}()
return to
}
然后用它来封装初始频道:
co := make(chan Object)
go ParseFile("file.xml", co)
Archive(ObjectToSaveable(co))