gpt4 book ai didi

go - 惯用地干掉 Go 中的公共(public)字段

转载 作者:IT王子 更新时间:2023-10-29 01:22:26 28 4
gpt4 key购买 nike

我正在为 API 编写客户端。一种方法 posts 返回用户帖子的数组。

  • 每个帖子都是八种不同类型之一。显然,这是一种"is"关系。
  • 帖子的许多字段,包括(除其他外)ID、URL 和时间戳,对于每种类型的帖子都是通用的。
  • 每种类型的帖子都有其类型独有的字段。例如,照片帖子将具有分辨率和标题。

在具有继承性的语言中,我会创建一个抽象基类 Post,然后将其子类化,为每种类型的帖子创建一个具体类。我会在基础 Post 中有一个构造函数或工厂方法,可能是 fromJson(),它接受一个 JSON 对象并提取所有公共(public)字段。然后我会在每个子类中重写它以提取专用字段,确保调用基本实现以干燥公共(public)字段的提取。

Go 没有继承,但是有组合。我定义了一个包含所有公共(public)字段的 Post 结构,然后我为每个类型创建了一个结构,它有一个匿名 Post 字段,以便它包含所有 Post 字段。例如,

type PhotoPost struct {
Post // which contains: ID int; URL string; etc
Caption string
Height int
Width int
/// etc
}

我的目标之一是让我客户端的用户可以轻松访问 Post 的公共(public)字段。所以我绝对不想让我正在编写的 Posts() 方法返回 interface{},因为任何时候有人想要获取所有的 ID例如,帖子,他们将不得不进行可怕的类型转换,这将是一种反复使用的模式,让我感到畏缩:

func GetIDs(posts []interface{}) []int {
var ids []int
for _, p := range posts {
switch p.(type) {
case PhotoPost:
ids = append(ids, p.(PhotoPost).ID)
//... repeat for the 7 other kinds of posts, and don't forget a default!
}
}
}

这太糟糕了。但是我不能让 Posts 返回 []Post,因为这样当需要更专业的数据时(对于像“给我这个用​​户的所有照片说明”这样的用例) posts"),它不会在那里(因为在 Go 中,PhotoPost 不是 Post,它 Post 及其字段。

此刻,我正在考虑让 Posts() 返回一个 PostCollection,这将是一个看起来像这样的结构,这样至少我可以避免上面的类型转换怪诞:

type PostCollection struct {                                                                                                                           
PhotoPosts []PhotoPost
// ...repeat for the others
}

但是“将所有帖子的所有 ID 放入一个 slice ”或类似的用例仍然非常麻烦。有人可以建议一种惯用的方法来处理这个问题吗?最好不需要反射?

我一直在考虑让每种类型的 Post 在返回其自己的 Post 的 TypedPost 接口(interface)中实现一个 PostData() 方法,但它看起来不像存在,除非我有一个命名的 一个看起来很奇怪的匿名类型(匿名这样我就可以说 somePhotoPost.ID 当我知道我有一个 PhotoPost 想要和 someTypedPost.PostData().ID 当我只知道我正在处理某种类型的 TypedPost 时。然后我会有 Posts() 返回[]TypedPost,有没有更好的办法?

最佳答案

为 Post 定义一个接口(interface) - 除了通过接口(interface)之外,不要访问公共(public)数据元素。

这是一个例子。请注意 Post 接口(interface),它定义了所有 帖子可以做什么(但不是它们包含的数据)。 playground

// Basic information about a post
type PostInfo struct {
ID int
URL string
}

// To satisfy the post interface
func (p *PostInfo) Info() *PostInfo {
return p
}

// Interface that defines what a Post can do
type Post interface {
Info() *PostInfo
}

type PhotoPost struct {
PostInfo // which contains: ID int; URL string; etc
Caption string
Height int
Width int
/// etc
}

func GetIDs(posts []Post) []int {
var ids []int
for _, p := range posts {
ids = append(ids, p.Info().ID)
}
return ids
}

func main() {
p0 := &PostInfo{1, "url0"}
p1 := &PhotoPost{PostInfo{2, "url1"}, "img", 16, 32}
posts := []Post{p0, p1}
fmt.Printf("Post IDs %v\n", GetIDs(posts))
}

如果您的代码有一个类型开关来切换您自己的对象,那么您在定义接口(interface)时就出错了。

请注意,您可以定义您的帖子子集满足的接口(interface),并使用类型转换来查看它们是否实现了它。

关于go - 惯用地干掉 Go 中的公共(public)字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24232385/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com