非结构类型如何扩展结构函数?

huangapple go评论78阅读模式
英文:

How can non-struct type extends struct functions

问题

更新:好的,我弄错了。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("无效的输入类型")
	}
	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
}

然而,我不知道如何将IntList扩展为CustomJSONType。我必须显式地为IntList定义ScanValue。即使在最好的情况下,我可以将ValueScan的实现包装为独立的函数,但仍然必须在IntList中编写ScanValue的签名。有没有建议可以像User一样简单地定义IntList

英文:

update: Ok I made it wrong. CustomJSONType's functions can not access the fields of the struct that it is embedded into, for which both User and IntList should define Scan and Value of their own or try other workarounds.


original post on 2021-6-21

I am using GORM and trying to define some custom types like User and IntList.

type User struct {
	Id	    int
	Name    string
	Email   string
}

type IntList []int

And as is known GORM custom type must implement Value and Scan functions. Here's what I did - I defined a CustomJSONType which implements Value and Scan like this:

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

To equip User with Value and Scan, all I have to do is to add a single line to the definition of User:

update: it won't work as CustomJSONType can't access fields of User

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

However, I have no idea how to extend IntList with CustomJSONType. I have to explicitly define Scan and Value for IntList. Even at best I can wrap the implementation of Value and Scan as independent functions but still have to write signatures for Scan and Value in IntList. Any suggestions to define IntList just as simple as User?

答案1

得分: 1

在golang中,没有"继承"的概念,只有组合。与普通的面向对象编程语言不同,结构体CustomJSONType无法访问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("无效的输入类型")
	}
	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
}

英文:

There is no "inherit" concept in golang but only combination. Don't like normal OOP language, the struct CustomJSONType can't access the data from IntList and User, so the method CustomJSONType.Value can't serialize other types than itself. If you want implement a method once and use it anywhere, I provide an idea bellow.

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

得分: 1

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

你可以在这里看到代码示例:
https://play.golang.org/p/MF5eMcgmeak

英文:

Not sure if I understood you correctly. But you can combine several types, including an array of ints, without creating a structure. They remain a type and are available in functions. But combining types requires a structure, which is why you cannot directly use array addressing.

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

You can see it here:
https://play.golang.org/p/MF5eMcgmeak

huangapple
  • 本文由 发表于 2021年6月21日 18:42:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/68066495.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定