为了账号安全,请及时绑定邮箱和手机立即绑定

切片struct!=它实现的接口切片?

/ 猿问

切片struct!=它实现的接口切片?

Go
天天世纪 2019-11-14 10:53:49

我有一个接口Model,该接口由struct实现Person。


要获取模型实例,我具有以下辅助函数:


func newModel(c string) Model {

    switch c {

    case "person":

        return newPerson()

    }

    return nil

}


func newPerson() *Person {

    return &Person{}

}

上面的方法允许我返回正确类型的Person实例(以后可以使用相同的方法轻松添加新模型)。


当我尝试执行类似的操作以返回模型切片时,出现错误。码:


func newModels(c string) []Model {

    switch c {

    case "person":

        return newPersons()

    }

    return nil

}


func newPersons() *[]Person {

    var models []Person

    return &models

}

去抱怨: cannot use newPersons() (type []Person) as type []Model in return argument


我的目标是回到请求任何机型的切片(是否[]Person,[]FutureModel,[]Terminator2000,W / E)。我缺少什么,如何正确实施这样的解决方案?


查看完整描述

3 回答

?
慕莱坞森

这非常类似于我刚刚回答的问题:https : //stackoverflow.com/a/12990540/727643


简短的答案是您是正确的。结构的片段不等于该结构实现的接口的片段。


A []Person和A []Model具有不同的内存布局。这是因为它们是切片的类型具有不同的内存布局。A Model是接口值,表示在内存中为两个字。一个单词代表类型信息,另一个单词代表数据。A Person是一个结构,其大小取决于它包含的字段。为了从转换[]Person为[]Model,您将需要遍历数组并对每个元素进行类型转换。


由于此转换是O(n)操作,并且会导致创建新的切片,因此Go拒绝隐式地执行此操作。您可以使用以下代码明确地做到这一点。


models := make([]Model, len(persons))

for i, v := range persons {

    models[i] = Model(v)

}

return models

就像dskinner指出的那样,您很可能需要一个切片指针而不是一个指向切片的指针。通常不需要指向切片的指针。


*[]Person        // pointer to slice

[]*Person        // slice of pointers


查看完整回答
反对 回复 2019-11-14
?
陪伴而非守候

也许这是您的返回类型的问题,*[]Person实际上应该是[]*Person引用切片的每个索引都是对a的引用Person,而切片[]本身就是对数组的引用。


查看以下示例:


package main


import (

    "fmt"

)


type Model interface {

    Name() string

}


type Person struct {}


func (p *Person) Name() string {

    return "Me"

}


func NewPersons() (models []*Person) {

    return models

}


func main() {

    var p Model

    p = new(Person)

    fmt.Println(p.Name())


    arr := NewPersons()

    arr = append(arr, new(Person))

    fmt.Println(arr[0].Name())

}


查看完整回答
反对 回复 2019-11-14
?
弑天下

使用go的接口的更好方法是不要让构造函数返回您可能习惯于从其他语言(如Java)返回的接口,而是让每个对象独立拥有一个构造函数,因为它们隐式实现了接口。


代替


newModel(type string) Model { ... }

你应该做


newPerson() *Person { ... }

newPolitician() *Politician { ... }

有Person和Politician两个实现的方法Model。您仍然可以使用Person或Politician任何地方,其中一个Model 被接受,但你也可以实现其他接口。


使用您的方法,您将只能Model进行手动转换为另一种接口类型。


假设我有一个Person实现该方法的方法Walk()和一个Model实现ShowOff(),以下将无法直接工作:


newModel("person").ShowOff()

newModel("person").Walk() // Does not compile, Model has no method Walk

但是,这将:


newPerson().ShowOff()

newPerson().Walk()


查看完整回答
反对 回复 2019-11-14

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信