去 |附加切片并发送到可变参数函数的高效且可读的方法
来源:stackoverflow
时间:2024-02-21 11:02:05 174浏览 收藏
编程并不是一个机械性的工作,而是需要有思考,有创新的工作,语法是固定的,但解决问题的思路则是依靠人的思维,这就需要我们坚持学习和更新自己的知识。今天golang学习网就整理分享《去 |附加切片并发送到可变参数函数的高效且可读的方法》,文章讲解的知识点主要包括,如果你对Golang方面的知识点感兴趣,就不要错过golang学习网,在这可以对大家的知识积累有所帮助,助力开发能力的提升。
假设我有以下功能管道:
func func3(opts ...functionobject) {
for _, opt := range opts {
opt()
}
}
func func2(opts ...functionobject) {
var functions []functionobject
functions = append(functions, somefunction3)
functions = append(functions, somefunction4)
...
...
...
func3(append(functions, opts...)...)
}
func func1(opts ...functionobject) {
var functions []functionobject
functions = append(functions, somefunction)
functions = append(functions, somefunction2)
...
...
...
func2(append(functions, opts...)...)
}
由于我想解决的问题继承的原因, functions 中的函数应该在 opts 中的函数之前调用,所以我不能只附加到 opts 但我必须前置 functions 到opts (通过 append(functions, opts...) ),然后再次使用 ... 将其发送到管道中的下一个函数,所以我得到了奇怪的表达式:
func2(append(functions, opts...)...)
我不知道它的效率如何,但我确信它看起来很奇怪,
一定有更好的方法来做到这一点,这就是我正在寻找的。p>
但是我很感激有关效率的附带解释:)
编辑:
我无法将参数类型从 opts ...functionobject 更改为 opts []functionobject (如@dev.bmax 在评论中建议的那样),因为我在现有代码库中进行了更改,所以我无法更改调用 func{ 的函数1,2,3}
- 我所说的“看起来很奇怪”不仅仅指“外观”,而是说两次执行此操作(省略号)看起来很奇怪,而且效率似乎很低(我错了吗?)
正确答案
在切片前面添加基本上效率很低,因为它需要以下内容的组合:
- 分配更大的后备数组
- 将项目移至切片末尾
- ...或两者兼而有之。
如果您可以将函数之间的调用约定更改为仅附加选项,然后反向处理它们,那么效率会更高。这可以避免重复地将项目移动到切片的末尾,并避免第一个之外的所有分配(如果提前分配了足够的空间)。
func func3(opts ...functionobject) {
for i := len(opts) - 1; i >= 0; i-- {
opts[i]()
}
}
注意: func3(opts ...functionobject) / func3(opts...) 和 func3(opts []functionobject) / func3(opts) 在性能上是等效的。前者是传递切片的有效语法糖。
但是,您提到您需要保留调用约定...
您的示例代码将导致每个函数内的第一个、第二个、第三个、第五个……附加分配 - 需要分配以使支持数组的大小加倍(对于小切片)。如果早期的附加没有创建足够的备用容量,append(functions, opts...) 也可能会分配。
辅助函数可以使代码更具可读性。它还可以重用 opts 支持数组中的备用容量:
func func2(opts ...functionobject) {
// 1-2 allocations. always allocate the variadic slice containings
// prepend items. prepend reallocates the backing array for `opts`
// if needed.
opts = prepend(opts, somefunction3, somefunction4)
func3(opts...)
}
// generics requires go1.18+. otherwise change t to functionobject.
func prepend[t any](base []t, items ...t) []t {
if size := len(items) + len(base); size <= cap(base) {
// extend base using spare slice capacity.
out := base[:size]
// move elements from the start to the end of the slice (handles overlaps).
copy(out[len(items):], base)
// copy prepended elements.
copy(out, items)
return out
}
return append(items, base...) // always re-allocate.
}
一些不带辅助函数的替代选项,可以更详细地描述分配:
// Directly allocate the items to prepend (2 allocations).
func func1(opts ...FunctionObject) {
// Allocate slice to prepend with no spare capacity, then append re-allocates the backing array
// since it is not large enough for the additional `opts`.
// In future, Go could allocate enough space initially to avoid the
// reallocation, but it doesn't do it yet (as of Go1.20rc1).
functions := append([]FunctionObject{
someFunction,
someFunction2,
...
}, opts...)
// Does not allocate -- the slice is simply passed to the next function.
func2(functions...)
}
// Minimise allocations (1 allocation).
func func2(opts ...FunctionObject) {
// Pre-allocate the required space to avoid any further append
// allocations within this function.
functions := make([]FunctionObject, 0, 2 + len(opts))
functions = append(functions, someFunction3)
functions = append(functions, someFunction4)
functions = append(functions, opts...)
func3(functions...)
}
您可以更进一步,重用 opts 中的备用容量,而无需分配包含要前置的项目的切片(每个函数 0-1 分配)。然而,这很复杂并且容易出错——我不推荐它。
以上就是《去 |附加切片并发送到可变参数函数的高效且可读的方法》的详细内容,更多关于的资料请关注golang学习网公众号!
-
502 收藏
-
502 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
139 收藏
-
204 收藏
-
325 收藏
-
478 收藏
-
486 收藏
-
439 收藏
-
357 收藏
-
352 收藏
-
101 收藏
-
440 收藏
-
212 收藏
-
143 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习