英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论