关于go:切片的通用remove()函数

Generic remove() function for slices

我有三个切片(foos,bars,bazs),每个切片都填充了不同类型的结构。为了删除一些样板代码,我想创建一个通用的remove(slice,struct)slice函数。与标准中提供的append()相反。

没有一个结构是指针,因此不需要将它们零。我有一个想法,就是使用接口来获得所需的结果,但却无济于事。当前的实现使用一个类型开关,然后使用一个near copy pasted remove()(例如下面的playground链接中)从切片中删除。随着我继续扩展这个项目,它将发展成更多的样板文件。

正在尝试的示例:https://play.golang.org/p/9upriip5m2

1
2
3
4
Function input: []slices, struct
Expected output:
    Modified (removed struct) []slices if struct is found
    Or, Unmodified []slices if it isn't.

如果它简单且易于实现。我想它已经在标准中存在了。然而,从经验丰富的专业人士那里得到建议,如果我想做的事情是可能的,那就没有什么坏处。

谢谢你抽出时间。


尝试使Go通用化是新Go开发人员的一大陷阱。停下来。您将保存五行代码:

1
2
3
4
5
for i := len(foos) - 1; i >= 0; i-- {
    if foos[i] == foo1 {
        foos = append(foos[:i], foos[i+1:]...)
    }
}

是的,在通用语言中,您可以将这五行包装成一个不错的stdlib方法,但go不是通用语言。用反射来做这件事是很慢的,但这并不是避免它的原因。思考是非常复杂的。很难把它弄好。你将花更多的时间去发现Value和追查奇怪的角落案例,而不是花12次重写这5行代码(包括修复你不小心剪切/粘贴错误的时间,还有一次你把i--搞砸)。写下来就行了。

仅仅编写代码就可以决定什么是平等。它允许您决定是停止搜索第一个匹配项,还是继续浏览整个列表。它允许你做这个程序需要做的事情,而不是专注于某一天某个通用程序可能需要的事情。

我喜欢通用编程。没有什么比在哈斯克尔创造一个优雅的折叠更让我快乐的了。但这不是前进的道路。在Go中,您通常只需编写代码,保持简单和明显,然后继续。

安迪指出了一个很好的观点,即如果你必须做大量的工作,那么list可能是一个更好的数据结构。我经常发现,当我有三种类型,似乎都有并行方法时,结果发现它们都应该是单个结构的一部分(您真的需要单独的列表吗?)但是在任何情况下,除非你有一个非常专门的问题,你真正的意思是"任何东西",而不是"这些简短的清单之一"。

(值得注意的是,你叫了append()。我认为在Go中不可能写append()。这就是为什么它必须是语言的一部分而不是stdlib函数。当我开始在围棋中工作时,我把这看作是语言上的一个显著缺陷。我在围棋里工作的时间越长,我发现它就越不重要。您只需编写代码并继续。)


我查看了您的示例代码及其错误。要了解更多关于interface slice的信息,请参考这个go wiki和slicetricks。

通用实现有点复杂,相反,您可以使用基于类型的实现。然而,基于类型的实现在样板文件上带来了更多的代码/重复性。

正如评论中提到的@stephen weinberg,您需要使用reflect包。

所以最好的出发点是:尝试这个库github.com/anzhihun/generic,并浏览库代码库,自己实现。此库使用反射。