dssu33392 2015-10-09 20:59
浏览 173
已采纳

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

What's an idiomatic way in Go to superclass similar (but not identical) data types in order to minimize code duplication? Trite example:

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)
}

Obviously there's more to it than that, but I'd love to be able to somehow superclass those so I only have to write and maintain one copy of particular functions. An interface seems to be the "right" way, but that leaves much to be desired (non-working example):

type Utmp interface {
    Time() time.Time
}

func User(u Utmp) string {
    return string(u.ut_user[:])
}

I've also considered embedding, but that seems a dead end too since Go is so strictly typed. Am I doomed to have multiple pieces of code that are identical in every way but the signature?

[edit]

Part of the complication is that I'm using encoding/binary.Read() to parse this data according to endianness (it's not just utmp records and not just Linux/BSD). To use that, the fields must be [exported] in the struct in the precise order they are on-disk. Hence I can't just embed the fields of another struct, as in some records they're in different order (and of differing sizes)

  • 写回答

2条回答 默认 最新

  • dongwu3596 2015-10-11 11:00
    关注

    I don't understand your comment about embedding. Here is how I'd do it (using embedding):

    package test
    
    import "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)
    }
    

    Any code importing the library can call User() method directly on LinuxUtmp and BsdUtmp objects directly as l.User() or b.User() without mentioning Utmp at all. You can even keep Utmp unexpected (as utmp) if you like.

    Check out Effective Go for details.

    You can even ensure that only the code meant for the relevant platform gets compiled in the binary, if you like. This blog has got some examples. In the interest of keeping things simple, I wouldn't bother going down that route if the platform specific code is not very big or there are other factors involved.

    For the sake of completeness, here is the official go build doc.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥30 Matlab打开默认名称带有/的光谱数据
  • ¥50 easyExcel模板 动态单元格合并列
  • ¥15 res.rows如何取值使用
  • ¥15 在odoo17开发环境中,怎么实现库存管理系统,或独立模块设计与AGV小车对接?开发方面应如何设计和开发?请详细解释MES或WMS在与AGV小车对接时需完成的设计和开发
  • ¥15 CSP算法实现EEG特征提取,哪一步错了?
  • ¥15 游戏盾如何溯源服务器真实ip?需要30个字。后面的字是凑数的
  • ¥15 vue3前端取消收藏的不会引用collectId
  • ¥15 delphi7 HMAC_SHA256方式加密
  • ¥15 关于#qt#的问题:我想实现qcustomplot完成坐标轴
  • ¥15 下列c语言代码为何输出了多余的空格