Golang 多态参数和返回值

huangapple go评论87阅读模式
英文:

Golang polymorphic parameters and returns

问题

func ToModelList(cats *[]*Cat) *[]*CatModel {
list := *cats
newModelList := []*CatModel{}
for i := range list {
obj := list[i]
newModelList = append(newModelList, obj.ToModel())
}
return &newModelList
}

func ToModelList(dogs *[]*Dog) *[]*DogModel {
list := *dogs
newModelList := []*DogModel{}
for i := range list {
obj := list[i]
newModelList = append(newModelList, obj.ToModel())
}
return &newModelList
}

有没有办法将这两个函数合并,这样我就可以这样做:

func ToModelList(objs *[]*interface{}) *[]*interface{} {
list := *objs
// 确定objs/list的结构体类型
newModelList := []*interface{}
// 将newModelList类型转换为正确的数组结构体类型
for i := range list {
obj := list[i]
// 根据objs的类型对obj进行类型转换
newModelList = append(newModelList, obj.ToModel())
}
return &newModelList
}

英文:

Say I have functions:

func ToModelList(cats *[]*Cat) *[]*CatModel {
    list := *cats
    newModelList := []*CatModel{}
    for i := range list {
        obj := obj[i]
        newModelList = append(newModelList, obj.ToModel())
    }
    return &newModelList
}

func ToModelList(dogs *[]*Dog) *[]*DogModel {
    list := *dogs
    newModelList := []*DogModel{}
    for i := range list {
        obj := obj[i]
        newModelList = append(newModelList, obj.ToModel())
    }
    return &newModelList
}

Is there a way to combine those two so I can do something like

func ToModelList(objs *[]*interface{}) *[]*interface{} {
    list := *objs
    // figure out what type struct type objs/list are
    newModelList := []*interface{}
    // type cast newModelList to the correct array struct type
    for i := range list {
        obj := obj[i]
        // type cast obj based on objs's type
        newModelList = append(newModelList, obj.ToModel())
    }
    return &newModelList
}

答案1

得分: 3

首先,切片已经是一个引用,除非你需要改变切片本身,否则不需要将其作为指针传递。

其次,interface{} 可以是一个对象或对象的指针,不需要使用 *interface{}。

我不确定你想要实现什么,但你可以像这样做:

package main

// Cat, Dog 的接口
type Object interface {
    ToModel() Model
}

// CatModel, DogModel 的接口
type Model interface {
    Name() string
}

type Cat struct {
    name string
}

func (c *Cat) ToModel() Model {
    return &CatModel{
        cat: c,
    }
}

type CatModel struct {
    cat *Cat
}

func (c *CatModel) Name() string {
    return c.cat.name
}

type Dog struct {
    name string
}

func (d *Dog) ToModel() Model {
    return &DogModel{
        dog: d,
    }
}

type DogModel struct {
    dog *Dog
}

func (d *DogModel) Name() string {
    return d.dog.name
}

func ToModelList(objs []Object) []Model {
    newModelList := []Model{}
    for _, obj := range objs {
        newModelList = append(newModelList, obj.ToModel())
    }
    return newModelList
}

func main() {
    cats := []Object{
        &Cat{name: "felix"},
        &Cat{name: "leo"},
        &Dog{name: "octave"},
    }
    modelList := ToModelList(cats)

    for _, model := range modelList {
        println(model.Name())
    }
}

你为 Cat、Dog 等定义了接口,以及为 Model 定义了接口。然后按照你的需求进行实现,使用 ToModelList() 函数非常简单。

英文:

First, slices are already a reference, unless you need to change the slice itself, you do not need to pass it as a pointer.
Second, an interface{} can be regardless an object or a pointer to an object. You do not need to have *interface{}.

I am not sure what you are trying to achieve but you could do something like this:

package main
// Interface for Cat, Dog
type Object interface {
ToModel() Model
}
// Interface for CatModel, DogModel
type Model interface {
Name() string
}
type Cat struct {
name string
}
func (c *Cat) ToModel() Model {
return &CatModel{
cat: c,
}
}
type CatModel struct {
cat *Cat
}
func (c *CatModel) Name() string {
return c.cat.name
}
type Dog struct {
name string
}
func (d *Dog) ToModel() Model {
return &DogModel{
dog: d,
}
}
type DogModel struct {
dog *Dog
}
func (d *DogModel) Name() string {
return d.dog.name
}
func ToModelList(objs []Object) []Model {
newModelList := []Model{}
for _, obj := range objs {
newModelList = append(newModelList, obj.ToModel())
}
return newModelList
}
func main() {
cats := []Object{
&Cat{name: "felix"},
&Cat{name: "leo"},
&Dog{name: "octave"},
}
modelList := ToModelList(cats)
for _, model := range modelList {
println(model.Name())
}
}

You define interfaces for your Cat, Dogs etc and for your Model. Then you implement them as you want and it is pretty straight forward to do ToModelList().

答案2

得分: 1

你可以让 *CatModel 和 *DogModel 都实现 PetModel 接口,并在函数签名中返回 []Pet。

func (cats []*Cat) []PetModel {
    ...
    return []PetModel{...}
}
func (dogs []*Dog) []PetModel {
    ...
    return []PetModel{...}
}

顺便说一下,在 Go 语言中返回指向切片的指针是没有意义的。

英文:

you can make *CatModel and *DogModel both implement type PetModel {} interface, and just return []Pet in function signature.

func (cats []*Cat) []PetModel {
...
return []*CatModel {...}
}
func (dogs []*Dog) []PetModel {
...
return []*DogModel {...}
}

BTW: return a pointer of a slice in golang is useless.

答案3

得分: 0

如果去除多余的赋值和不必要的切片指针,你会发现剩下的代码很少,而为每个模型类型复制代码看起来并不那么糟糕。

func CatsToCatModels(cats []*Cat) []*CatModel {
    var result []*CatModel
    for _, cat := range cats {
        result = append(result, cat.ToModel())
    }
    return result
}

除非这段代码在很多地方都被使用,否则我建议将其内联,因为这是一段简单的代码,内联后只有4行。

是的,你可以用interface{}替换所有类型,使代码变得通用,但我认为在这里这样做并不是一个好的权衡。

英文:

If you strip away redundant assignments, and unnecessary pointers-to-slices, you'll find you have little code left, and duplicating it for each of your model types doesn't look so bad.

func CatsToCatModels(cats []*Cat) []*CatModel {
var result []*CatModel
for _, cat := range cats {
result = append(result, cat.ToModel())
}
return result
}

Unless this code is used in a lot of places I'd also consider just inlining it, since it's trivial code and only 4 lines when inlined.

Yes, you can replace all the types with interface{} and make the code generic, but I don't think it's a good tradeoff here.

huangapple
  • 本文由 发表于 2014年2月8日 04:06:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/21636805.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定