【问题标题】:How can non-struct type extends struct functions非结构类型如何扩展结构函数
【发布时间】:2021-06-21 10:42:54
【问题描述】:

更新:好吧,我弄错了。 CustomJSONType 的函数无法访问它所嵌入的结构的字段,UserIntList 都应该定义自己的 ScanValue 或尝试其他解决方法。


原帖于 2021-6-21

我正在使用 GORM 并尝试定义一些自定义类型,例如 UserIntList

type User struct {
    Id      int
    Name    string
    Email   string
}

type IntList []int

众所周知,GORM 自定义类型必须实现 ValueScan 函数。这就是我所做的——我定义了一个CustomJSONType,它实现了ValueScan,如下所示:

type CustomJSONType struct {}

func (t *CustomJSONType) Scan(src interface{}) error {
    bytes, ok := src.([]byte)
    if !ok {
        return errors.New("invalid input type")
    }
    err := json.Unmarshal(bytes, t)
    if err != nil{
        return err
    }
    return nil
}

func (t CustomJSONType) Value() (driver.Value, error) {
    bytes, err := json.Marshal(t)

    if err != nil {
        return []byte{}, err
    }
    return bytes, err
}

func (t CustomJSONType) GormDataType() string {
    return "json"
}

要为User 配备ValueScan,我所要做的就是在User 的定义中添加一行:

更新:由于CustomJSONType 无法访问User 的字段,它将无法工作

type User struct {
    CustomJSONType
    Id      int
    Name    string
    Email   string
}

但是,我不知道如何用CustomJSONType 扩展IntList。我必须为IntList 明确定义ScanValue。即使充其量我可以将ValueScan 的实现包装为独立的函数,但仍然必须在IntList 中为ScanValue 编写签名。将IntList 定义为与User 一样简单的任何建议?

【问题讨论】:

  • 结构类型是唯一允许嵌入的具体类型。由于IntList 不是结构类型,因此您不能像为User 那样在其中嵌入CustomJSONType
  • 你想用 empty 结构类型上的 ScanValue 实现来完成什么?如果您希望 CustomJSONType “继承”它所嵌入的结构的字段,那么您应该知道这不是嵌入所做的。在 Go 中没有类型扩展。
  • 基本上你必须为这两种类型显式定义ScanValue - IntList UserCustomJSONType 没用,它所做的只是满足一个接口,但实现什么也不做,因为这两种方法中的 t 都是 empty 结构或指向空结构的指针。
  • @mkopriva 谢谢!我没有在运行时测试我的代码。
  • @mkopriva 您可以通过将空值结构作为第一个成员嵌入一个带有指针接收器的方法来伪造 Go 中的方法扩展,您可以在其中使用 unsafe.Pointer 将接收器的类型更改为您的结构嵌入。至少在 Go 2 之前:github.com/golang/go/issues/18617 不推荐,但它有效。

标签: go go-gorm


【解决方案1】:

golang 中没有“继承”的概念,只有组合。不喜欢普通的OOP语言,structCustomJSONType不能访问IntListUser的数据,所以方法CustomJSONType.Value不能序列化除自身以外的其他类型。如果你想实现一个方法一次并在任何地方使用它,我在下面提供一个想法。

package main

import (
    "database/sql/driver"
    "encoding/json"
    "errors"
    "fmt"
)

type CustomJSONType struct {
    data interface{}
}

func (t *CustomJSONType) Scan(src interface{}) error {
    bytes, ok := src.([]byte)
    if !ok {
        return errors.New("invalid input type")
    }
    err := json.Unmarshal(bytes, t.data)
    if err != nil{
        return err
    }
    return nil
}

func (t CustomJSONType) Value() (driver.Value, error) {
    bytes, err := json.Marshal(t.data)

    if err != nil {
        return []byte{}, err
    }
    return bytes, err
}

func (t CustomJSONType) GormDataType() string {
    return "json"
}

type User struct {
    Id      int
    Name    string
    Email   string
}

type Project struct {
    user CustomJSONType
}

func (p *Project) SetUser(u User) {
    p.user.data = u
}

func (p *Project) GetUser() User {
    user := p.user.data.(User)
    return user
}

【讨论】:

    【解决方案2】:

    不确定我是否理解正确。但是您可以组合多种类型,包括整数数组,而无需创建结构。它们仍然是一种类型并且在函数中可用。但是组合类型需要一个结构,这就是为什么不能直接使用数组寻址的原因。

    type IntArr []int
    type AnyStruct struct{
        Uses bool
    }
    type TestIntArrStruct struct{
        IntArr
        AnyStruct
    }
    func(arr *IntArr) Add(i ...int){
        *arr = append(*arr, i...)
    }
    func(anyStruct *AnyStruct) Invert(){
        anyStruct.Uses = !anyStruct.Uses
    }
    var a TestIntArrStruct
    a.Add(1,2,3)
    a.Invert()
    

    你可以在这里看到它: https://play.golang.org/p/MF5eMcgmeak

    【讨论】:

      猜你喜欢
      • 2020-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-30
      • 2012-08-06
      • 1970-01-01
      • 2017-09-01
      相关资源
      最近更新 更多