返回自定义界面片断的函数

问题描述 投票:0回答:2

一开始,我想给大家介绍一下,因为我觉得我缺少一些Golang的核心概念。

在我的应用中,很多模型都会有一个叫做GetByUserId的方法。我创建了需要这个方法的接口(UserCreatedEntity),这样我就可以为每种类型的记录创建Controller的GetUserRecords方法工厂。

router.Handle("/ideas/mine",
        middlewares.AuthUser(controllers.GetMineFactory(&models.Idea{}))).Methods("POST")

router.Handle("/votes/mine",
        middlewares.AuthUser(controllers.GetMineFactory(&models.Vote{}))).Methods("POST")

router.Handle("/someNewType/mine",
        middlewares.AuthUser(controllers.GetMineFactory(&models.SomeNewType{}))).Methods("POST")

这是我的接口的样子:

type UserCreatedEntity interface {
    GetByUserId(userId uint) []UserCreatedEntity
}

和实现。

func (idea *Idea) GetByUserId(userId uint) []UserCreatedEntity {
    ideas := []Idea{}
    GetDB().
        Table("ideas").
        /** Query removed to make code less confusing **/
        Scan(ideas)

    return ideas
}

很明显,这是不工作的(有指针片的版本也不工作)。问题是--如果我只返回一条记录,这段代码就会工作--就像这样(很明显,在接口中也改变了签名)。

func (idea *Idea) GetByUserId(userId uint) UserCreatedEntity {
    idea := &Idea{}
    GetDB().
        Table("ideas").
        /** Query removed to make code less confusing **/
        First(idea)

    return idea
}

如何让它像slice一样工作?正如我所说,我怀疑我缺少一些重要的知识。所以,深入的解释将是真棒。

解决办法。

func (idea *Idea) GetByUserId(userId uint) []UserCreatedEntity {
    ideas := []*Idea{}
    GetDB().
        Table("ideas").
        Select("problems.name AS problem_name, ideas.id, ideas.problem_id, ideas.action_description, ideas.results_description, ideas.money_price, ideas.time_price, ideas.is_published").
        Joins("INNER JOIN problems ON ideas.problem_id = problems.id").
        Where("ideas.user_id = ?", userId).
        Scan(&ideas)

    uces := make([]UserCreatedEntity, len(ideas))
    for i, idea := range ideas {
        uces[i] = idea
    }
    return uces
}
go interface slice
2个回答
1
投票

接口是动态的。涉及接口的复合类型不是。

UserCreatedEntity 是一个接口,而 Idea 满足接口,所以你可以返回一个 Idea 的函数,其签名的返回类型为 UserCreatedEntity.

[]UserCreatedEntity 是一片 UserCreatedEntity,而不是一个接口。唯一可以返回的类型是 []UserCreatedEntity. []Idea 是一种不同的类型(片的 Idea). 你可以填写一个 []UserCreatedEntityIdea 元素,因为每个元素都是类型为 UserCreatedEntity,这也是一个接口和 Idea 是允许的。

同样地: func() UserCreatedEntity 是一个类型 "函数,它返回 UserCreatedEntity". 你不能用"。func() Idea 因为那是一个不同的类型。但你可以返回一个 Ideafunc() UserCreatedEntity 因为 Idea 是一个 UserCreatedEntity.

如果你没有使用 Scan 这里,它可能使用反射,修复方法是将你的本地片断声明为 []UserCreatedEntity 而不是 []Idea. 由于您使用的是 Scan而您必须扫描到一个 []Idea然后在它上面遍历,把所有的元素复制到一个叫做 []UserCreatedEntity 并将其返回。


3
投票

在编程语言理论中,这被称为 差异Go中不支持. 更多详情请见 本建议.

具体来说,返回类型是不共通的。一片 T 并没有实现片区的 I 纵然 T 实施 I.

上面链接的FAQ条目提出了这个变通方法。

有必要将元素分别复制到目标分片中。这个例子将 int 的分片转换为 interface{} 的分片。

t := []int{1, 2, 3, 4}
s := make([]interface{}, len(t))
for i, v := range t {
    s[i] = v
}

虽然在你的例子中,正确的解决方案可能不同。

© www.soinside.com 2019 - 2024. All rights reserved.