英文:
Go - Merging 2 functions whose only difference is the arguments type
问题
我有这两个几乎完全相同的函数:
第一个:
func mergeSlicesOfRequestObjects(aSliceDestination *[]RequestObject, aSliceSource []RequestObject) {
for _, oSliceSourceItem := range aSliceSource {
// 获取当前键
iIndexSourceItemFound := -1
for iIndexAttribute, oSliceDestinationItem := range *aSliceDestination {
if oSliceSourceItem.Key == oSliceDestinationItem.Key {
iIndexSourceItemFound = iIndexAttribute
break
}
}
// 更新属性
if iIndexSourceItemFound == -1 {
*aSliceDestination = append(*aSliceDestination, oSliceSourceItem)
}
}
}
第二个:
func mergeSlicesOfResponseObjects(aSliceDestination *[]ResponseObject, aSliceSource []ResponseObject) {
for _, oSliceSourceItem := range aSliceSource {
// 获取当前键
iIndexSourceItemFound := -1
for iIndexAttribute, oSliceDestinationItem := range *aSliceDestination {
if oSliceSourceItem.Key == oSliceDestinationItem.Key {
iIndexSourceItemFound = iIndexAttribute
break
}
}
// 更新属性
if iIndexSourceItemFound == -1 {
*aSliceDestination = append(*aSliceDestination, oSliceSourceItem)
}
}
}
如你所见,这两个函数的唯一区别是参数的结构类型。
所以我的问题是:有没有办法将这两个函数合并成一个函数?
我尝试使用接口,但是我无法弄清楚...
提前感谢你的回答
祝好
编辑
我已经实现了这个答案,但是我遇到了错误。这是我做的:
type Request struct {
Headers []RequestObject
}
type RequestObject struct {
Key string
}
type Keyer interface {
GetKey() string
}
func (oRequestObject RequestObject) GetKey() string {
return oRequestObject.Key
}
func mergeKeyers(aDst *[]Keyer, aSrc []Keyer) {
// 逻辑
}
func test() {
// rDst 和 rSrc 是 Request 结构体
mergeKeyers(&rDst.Headers, rSrc.Headers)
}
当执行 test() 时,我得到了以下错误:
cannot use &rDst.Headers (type *[]RequestObject) as type *[]Keyer in argument to mergeKeyers
cannot use rSrc.Headers (type []RequestObject) as type []Keyer in argument to mergeKeyers
有任何想法为什么会出现这个错误?
英文:
I have those 2 almost exact functions :
Number 1:
func mergeSlicesOfRequestObjects(aSliceDestination *[]RequestObject, aSliceSource []RequestObject) {
for _, oSliceSourceItem := range aSliceSource {
// Get current key
iIndexSourceItemFound := -1
for iIndexAttribute, oSliceDestinationItem := range *aSliceDestination {
if oSliceSourceItem.Key == oSliceDestinationItem.Key {
iIndexSourceItemFound = iIndexAttribute
break
}
}
// Update attribute
if iIndexSourceItemFound == -1 {
*aSliceDestination = append(*aSliceDestination, oSliceSourceItem)
}
}
}
Number 2:
func mergeSlicesOfResponseObjects(aSliceDestination *[]ResponseObject, aSliceSource []ResponseObject) {
for _, oSliceSourceItem := range aSliceSource {
// Get current key
iIndexSourceItemFound := -1
for iIndexAttribute, oSliceDestinationItem := range *aSliceDestination {
if oSliceSourceItem.Key == oSliceDestinationItem.Key {
iIndexSourceItemFound = iIndexAttribute
break
}
}
// Update attribute
if iIndexSourceItemFound == -1 {
*aSliceDestination = append(*aSliceDestination, oSliceSourceItem)
}
}
}
As you can see the only difference is the struct type of the arguments of the functions.
So here is my question : is there any way to merge those 2 functions into one ?
I've tried using interfaces but I can't figure it out...
Thanks for all the answer in advance
Cheers
EDIT
I've implemented thwd answer but I'm getting errors. Here's what I've done:
type Request struct {
Headers []RequestObject
}
type RequestObject {
Key string
}
type Keyer interface {
GetKey() string
}
func (oRequestObject RequestObject) GetKey() string {
return oRequestObject.Key
}
func mergeKeyers(aDst *[]Keyer, aSrc []Keyer) {
// Logic
}
func test() {
// rDst and rSrc are Request struct
mergeKeyers(&rDst.Headers, rSrc.Headers)
}
And I'm getting the following errors when executing test():
cannot use &rDst.Headers (type *[]RequestObject) as type *[]Keyer in argument to mergeKeyers
cannot use rSrc.Headers (type []RequestObject) as type []Keyer in argument to mergeKeyers
Any idea why ?
答案1
得分: 4
定义一个接口:
type Keyer interface {
Key() int // 或者 Key 字段的任何类型
}
然后在两种类型上实现该接口:
func (r RequestObject) Key() int {
return r.Key
}
func (r ResponseObject) Key() int {
return r.Key
}
并且重写你的函数以接受这个接口(不使用匈牙利命名法和无尽的长变量名):
func mergeKeyers(dst *[]Keyer, src []Keyer) {
for _, s := range src {
f := -1
for i, d := range *dst {
if s.Key() == d.Key() {
f = i
break
}
}
if f == -1 {
*dst = append(*dst, s)
}
}
}
还要考虑 Dave C 的评论:
你使用了一个 O(n*m) 的算法,而你可以使用一个 O(n+m) 的算法。
我将把优化代码的工作留给你。
编辑以回答你的第二个问题:
类型 *[]RequestObject
和 *[]Keyer
是不同的,不能互换。你需要做的是将你的 RequestObjects 切片转换为 Keyers 切片。
这很简单,只需遍历 []RequestObject
并将每个条目分配给类型为 []Keyer
的新条目。
另请参阅以下答案:
- https://stackoverflow.com/questions/12753805/type-converting-slices-of-interfaces-in-go
- https://stackoverflow.com/questions/11924196/convert-between-slices-of-different-types
英文:
Define an interface:
type Keyer interface {
Key() int // or whatever type the Key field has
}
Then implement the interface on both types:
func (r RequestObject) Key() int {
return r.Key
}
func (r ResponseObject) Key() int {
return r.Key
}
And rewrite your function to take this interface (and not use hungarian notation and endlessly long variable names):
func mergeKeyers(dst *[]Keyer, src []Keyer) {
for _, s := range src {
f := -1
for i, d := range *dst {
if s.Key() == d.Key() {
f = i
break
}
}
if f == -1 {
*dst = append(*dst, s)
}
}
}
Also, take into account Dave C's comment:
> you have an O(n×m) algorithm where you could use a O(n+m) one.
I'll leave it up to you to optimize your code in that way.
<hr>
Edit to address your second question:
The types *[]RequestObject
and *[]Keyer
are distinct and not interchangeable. What you need to do is convert your slice of RequestObjects to a slice of Keyers.
This is as easy as iterating over the []RequestObject
and assigning each entry to a new entry in a value of type []Keyer
.
See also these answers:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论