猿问

Golang:代码重复和类似的结构

Go to superclass 类似(但不相同)的数据类型以最小化代码重复的惯用方法是什么?老生常谈的例子:


import "time"


type LinuxUtmp struct {

    ut_type uint16

    _       [2]byte

    ut_pid  uint32

    ut_line [32]byte

    ut_id   [4]byte

    ut_user [32]byte

    ut_host [256]byte

    exit_status [2]uint32

    tv_sec  uint32

    tv_usec uint32

    ...

}


func (l LinuxUtmp) User() string {

    return string(l.ut_user[:])

}


func (l LinuxUtmp) Time() time.Time {

    return time.Unix(int64(l.tv_sec), int64(l.tv_usec))

}


type BsdUtmp struct {

    ut_line [8]char

    ut_name [16]char

    ut_host [16]char

    ut_time uint32

}


func (b BsdUtmp) User() string {

    return string(b.ut_user[:])

}


func (b BsdUtmp) Time() time.Time {

    return time.Unix(int64(b.ut_time), 0)

}

显然还有更多的东西,但我希望能够以某种方式超类那些,所以我只需要编写和维护特定函数的一个副本。接口似乎是“正确”的方式,但这还有很多不足之处(非工作示例):


type Utmp interface {

    Time() time.Time

}


func User(u Utmp) string {

    return string(u.ut_user[:])

}

我也考虑过嵌入,但这似乎也是一个死胡同,因为 Go 的类型如此严格。我是否注定要拥有除签名外在各方面都相同的多段代码?


[编辑]


部分复杂之处在于我使用 encoding/binary.Read() 根据字节序解析这些数据(不仅仅是 utmp 记录,而不仅仅是 Linux/BSD)。要使用它,字段必须按照它们在磁盘上的精确顺序在结构中[导出]。因此我不能只嵌入另一个结构的字段,因为在某些记录中它们的顺序不同(并且大小不同)


幕布斯7119047
浏览 197回答 2
2回答

萧十郎

我不明白您对嵌入的评论。这是我的方法(使用嵌入):package testimport "time"type Utmp struct {    // Common fields}func (u Utmp) User() {    return string(l.ut_user[:])}type LinuxUtmp struct {    Utmp    // Linux specific fields}func (l LinuxUtmp) Time() time.Time {    return time.Unix(int64(l.tv_sec), int64(l.tv_usec))}type BsdUtmp struct {    Utmp    // BSD specific fields}func (b BsdUtmp) Time() time.Time {    return time.Unix(int64(b.ut_time), 0)}任何导入库的代码都可以User()直接调用方法LinuxUtmp和BsdUtmp对象,l.User()无论b.User()是否提及Utmp。如果您愿意,您甚至可以保留Utmp出乎意料的 (as utmp)。查看Effective Go了解详情。如果您愿意,您甚至可以确保只有适用于相关平台的代码才能在二进制文件中编译。这个博客有一些例子。为了保持简单,如果特定于平台的代码不是很大或涉及其他因素,我不会费心走这条路。为了完整起见,这里是官方的go build文档。

烙印99

如果遇到某些东西类型不一样的问题,可以让Time和User函数运行在一个封装了linux和bsd功能的接口上。如果您不喜欢那样,您可以生成代码以避免重复。
随时随地看视频慕课网APP

相关分类

Go
我要回答