为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
qq_笑_17 2021-12-07 18:37:46
我是一名经验丰富的 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)}
查看完整描述

3 回答

?
扬帆大鱼

TA贡献1799条经验 获得超9个赞

不要这样做。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

}


查看完整回答
反对 回复 2021-12-07
?
素胚勾勒不出你

TA贡献1827条经验 获得超9个赞

就像使用json.Marshalerand 一样json.Unamrshaler,您也可以实现接口。gocql.Marshaler gocql.Unamrshaler


func (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 的上下文中未经测试,但这会与自身进行往返)


查看完整回答
反对 回复 2021-12-07
?
Smart猫小萌

TA贡献1911条经验 获得超7个赞

不幸的是,这在 Go 中不起作用。您最好的选择是创建一些导入和导出方法,以便您可以将 PythonTime 转换为 time.Time,反之亦然。这将为您提供所需的灵活性以及与其他库的兼容性。


package main


import (


    "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.PythonTime


2016-02-04 14:32:17 -0700 MST time.Time


查看完整回答
反对 回复 2021-12-07
  • 3 回答
  • 0 关注
  • 196 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信