【问题标题】:Function that takes different type of struct采用不同类型结构的函数
【发布时间】:2016-08-22 13:11:12
【问题描述】:

我想知道如何将以下函数lengthAAlengthBB 简化为一个函数。请注意,在这两个函数中,它只是计算数组的长度,它只是一个示例,可能比这更复杂。理想情况下,我只想要一个用于相同目的的函数(在本例中为len),但可以将不同的struct 作为变量。

type A struct {
   id string
}

type AA struct {
   ids []A
}

type B struct {
   id string
   value bool
}

type BB struct {
   ids []B
}

func lengthAA(aa AA) int {
   return len(aa)
}

func lengthBB(bb BB) int {
   return len(bb)
}

【问题讨论】:

  • 您可以将返回类型指定为Interface。如下正确回答

标签: go go-reflect


【解决方案1】:

Go 的做法是让AABB 实现一个通用方法。然后length 将接受包含相同函数签名的接口。示例:

package main

import (
    "fmt"
)

type Lengther interface {
    Length() int
}

type A struct {
    id string
}

type AA struct {
    ids []A
}

func (a *AA) Length() int {
    return len(a.ids)
}

type B struct {
    id    string
    value bool
}

type BB struct {
    ids []B
}

func (b *BB) Length() int {
    return len(b.ids)
}

func length(l Lengther) int {
    return l.Length()
}

func main() {
    aa := &AA{
        ids: make([]A, 10),
    }
    bb := &BB{
        ids: make([]B, 34),
    }
    fmt.Println(length(aa))
    fmt.Println(length(bb))
}

https://play.golang.org/p/DdxP5lFcZi

【讨论】:

    【解决方案2】:

    1- 使用两个单独的接收器方法length() 就像这个工作示例代码(这是惯用的 Go):

    package main
    
    import "fmt"
    
    func (v *AA) length() int {
        return len(v.ids)
    }
    func (v *BB) length() int {
        return len(v.ids)
    }
    
    func main() {
        aa := AA{[]A{A{"id"}, A{"id2"}}}
        fmt.Println(aa.length()) // 2
        bb := BB{[]B{B{"id", true}, B{"id2", true}}}
        fmt.Println(bb.length()) // 2
    }
    
    type A struct {
        id string
    }
    
    type AA struct {
        ids []A
    }
    
    type B struct {
        id    string
        value bool
    }
    
    type BB struct {
        ids []B
    }
    

    2- 使用一个length(aa interface{}) 函数,就像这个工作示例代码(在某些用例中这很有用):

    package main
    
    import "fmt"
    
    func length(aa interface{}) int {
        switch v := aa.(type) {
        case AA:
            return len(v.ids)
        case BB:
            return len(v.ids)
        }
        return -1
    }
    
    func main() {
        aa := AA{[]A{A{"id"}, A{"id2"}}}
        fmt.Println(length(aa)) // 2
        bb := BB{[]B{B{"id", true}, B{"id2", true}}}
        fmt.Println(length(bb)) // 2
    }
    
    type A struct {
        id string
    }
    
    type AA struct {
        ids []A
    }
    
    type B struct {
        id    string
        value bool
    }
    
    type BB struct {
        ids []B
    }
    

    3- 使用reflect 和一个length(v interface{}) 函数,就像这个工作示例代码(在某些用例中这很有用):

    package main
    
    import "fmt"
    import "reflect"
    
    func length(v interface{}) int {
        return reflect.ValueOf(v).FieldByName("ids").Len()
    }
    
    func main() {
        aa := AA{[]A{A{"id"}, A{"id2"}}}
        fmt.Println(length(aa)) // 2
        bb := BB{[]B{B{"id", true}, B{"id2", true}}}
        fmt.Println(length(bb)) // 2
    }
    
    type A struct {
        id string
    }
    
    type AA struct {
        ids []A
    }
    
    type B struct {
        id    string
        value bool
    }
    
    type BB struct {
        ids []B
    }
    

    输出:

    2
    2
    

    【讨论】:

      【解决方案3】:

      此代码实际上不会编译,因为len(aa) 会将结构传递给len,这将失败。但我想我明白了你想要做的事情,最好的方法是使用 Go 最接近继承的东西,这实际上只是结构嵌入。

      通过制作一个可嵌入的结构,并让每个具有类似功能的结构嵌入它,您可以减少代码的行数,尽管“简化”可能有点牵强。

      type HasIDs struct {
         Ids []string
      }
      
      type AA struct {   
         HasIDs
         OtherValues []int
      }
      
      type BB struct {
         HasIDs
         OtherValues []byte
      }
      

      此时,AABB 两个结构的值都为 Ids []string。现在您可以为HasIDs 结构提供两个结构都应该能够调用的方法。

      func (hasIds HasIDs) length() {
          return len(hasIds.Ids)
      }
      

      然后在嵌入该结构的任一结构上调用该方法。

      a1 := AA{}
      aLength := a1.length()
      

      这是一个工作代码示例:https://play.golang.org/p/ys_CN_L_cr

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-11-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-08
        • 2016-01-05
        • 1970-01-01
        相关资源
        最近更新 更多