猿问

在检查 Golang 类型时创建看起来像另一个的自定义类型

我是一名经验丰富的 Python 程序员,但我对 Golang 还是个新手,所以如果这是一个明显或愚蠢的问题,我深表歉意。但是我正在尝试创建我自己的类型,我希望它的行为与基类型完全相同,但有几个方法被覆盖。原因是因为我使用的几个库正在检查类型time.Time,我希望它匹配。


type PythonTime struct {

    time.Time

}


var pythonTimeFormatStr = "2006-01-02 15:04:05-0700"


func (self *PythonTime) UnmarshalJSON(b []byte) (err error) {

    // removes prepending/trailing " in the string

    if b[0] == '"' && b[len(b)-1] == '"' {

        b = b[1 : len(b)-1]

    }

    self.Time, err = time.Parse(pythonTimeFormatStr, string(b))

    return

}


func (self *PythonTime) MarshalJSON() ([]byte, error) {

    return []byte(self.Time.Format(pythonTimeFormatStr)), nil

}


type OtherType struct {

    Uuid     string     `json:"uuid`

    Second   PythonTime `json:"second"`

    Location string     `json:"location"`

    Action   string     `json:"action"`

    Duration int        `json:"duration"`

    Value    string     `json:"value"`

}

因此,上述内容适用于编组和解组 JSON。但是,对于我正在使用的库(gocql 和 cqlr),他们正在检查类型是否为time.Time类型,以便他们可以在将其放入 C* 之前进行一些其他修改。我如何让我的PythonTime类型等同于显示time.Time 或覆盖对象的默认编组/解组,time.Time只是为了使用我的OtherType对象?


我的临时解决方案是修改他们的代码,并为与PythonTime类型做同样事情的time.Time类型添加一个特例。但是,这导致我循环导入并且不是最佳解决方案。这是我修改后的代码。


func marshalTimestamp(info TypeInfo, value interface{}) ([]byte, error) {

    switch v := value.(type) {

    case Marshaler:

        return v.MarshalCQL(info)

    case int64:

        return encBigInt(v), nil

    case time.Time:

        if v.IsZero() {

            return []byte{}, nil

        }

        x := int64(v.UTC().Unix()*1e3) + int64(v.UTC().Nanosecond()/1e6)

        return encBigInt(x), nil

    case models.PythonTime:

        x := int64(v.UTC().Unix()*1e3) + int64(v.UTC().Nanosecond()/1e6)

        return encBigInt(x), nil

    }


    if value == nil {

        return nil, nil

    }


    rv := reflect.ValueOf(value)

    switch rv.Type().Kind() {

    case reflect.Int64:

        return encBigInt(rv.Int()), nil

    }

    return nil, marshalErrorf("can not marshal %T into %s", value, info)

}


qq_笑_17
浏览 197回答 3
3回答

扬帆大鱼

不要这样做。time.Time当您应该检查对象是否满足接口时,您正在检查对象。type TimeLike interface {    Day() int    Format(string) string    ...  // whatever makes a "time" object to your code!    // looks like in this case it's    UTC() time.Time    IsZero() bool}那么任何需要 a 的代码time.Time都可以用 a 替换,而是PythonTime期待 a TimeLike。function Foo(value interface{}) int {    switch v := value.(type) {    case TimeLike:        return v.Day()  // works for either time.Time or models.PythonTime    }    return 0}

素胚勾勒不出你

就像使用json.Marshalerand 一样json.Unamrshaler,您也可以实现接口。gocql.Marshaler gocql.Unamrshalerfunc (t *PythonTime) MarshalCQL(info gocql.TypeInfo) ([]byte, error) {    b := make([]byte, 8)    x := t.UnixNano() / int64(time.Millisecond)    binary.BigEndian.PutUint64(b, uint64(x))    return b, nil}func (t *PythonTime) UnmarshalCQL(info gocql.TypeInfo, data []byte) error {    x := int64(binary.BigEndian.Uint64(data)) * int64(time.Millisecond)    t.Time = time.Unix(0, x)    return nil}(注意,在 CQL 的上下文中未经测试,但这会与自身进行往返)

Smart猫小萌

不幸的是,这在 Go 中不起作用。您最好的选择是创建一些导入和导出方法,以便您可以将 PythonTime 转换为 time.Time,反之亦然。这将为您提供所需的灵活性以及与其他库的兼容性。package mainimport (    "fmt"    "reflect"    "time")func main() {    p, e := NewFromTime(time.Now())    if e != nil {        panic(e)    }    v, e := p.MarshalJSON()    if e != nil {         panic(e)    }    fmt.Println(string(v), reflect.TypeOf(p))    t, e := p.GetTime()    if e != nil {        panic(e)    }    fmt.Println(t.String(), reflect.TypeOf(t))}type PythonTime struct {    time.Time}var pythonTimeFormatStr = "2006-01-02 15:04:05-0700"func NewFromTime(t time.Time) (*PythonTime, error) {b, e := t.GobEncode()if e != nil {    return nil, e}p := new(PythonTime)e = p.GobDecode(b)if e != nil {    return nil, e}    return p, nil}func (self *PythonTime) GetTime() (time.Time, error) {    return time.Parse(pythonTimeFormatStr, self.Format(pythonTimeFormatStr))}func (self *PythonTime) UnmarshalJSON(b []byte) (err error) {    // removes prepending/trailing " in the string    if b[0] == '"' && b[len(b)-1] == '"' {        b = b[1 : len(b)-1]    }    self.Time, err = time.Parse(pythonTimeFormatStr, string(b))    return}func (self *PythonTime) MarshalJSON() ([]byte, error) {    return []byte(self.Time.Format(pythonTimeFormatStr)), nil}那应该给出这样的输出:2016-02-04 14:32:17-0700 *main.PythonTime2016-02-04 14:32:17 -0700 MST time.Time
随时随地看视频慕课网APP

相关分类

Go
我要回答