# #go #go-gorm
Вопрос:
обновление: Хорошо, я сделал это неправильно. CustomJSONType
функции s не могут получить доступ к полям структуры, в которую они встроены, для которых оба User
и IntList
должны определить Scan
и Value
самостоятельно или попробовать другие обходные пути.
оригинальное сообщение 2021-6-21
Я использую GORM и пытаюсь определить некоторые пользовательские типы, такие как User
и IntList
.
type User struct {
Id int
Name string
Email string
}
type IntList []int
И, как известно, пользовательский тип GORM должен реализовывать Value
и Scan
функции. Вот что я сделал — я определил CustomJSONType
, что реализует Value
и Scan
как это:
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
Value
и Scan
все , что мне нужно сделать, это добавить одну строку в определение User
:
обновление: это не будет работать, так как CustomJSONType
не может получить доступ к полям User
type User struct {
CustomJSONType
Id int
Name string
Email string
}
Однако я понятия не имею, как это расширить IntList
CustomJSONType
. Я должен явно определить Scan
и Value
для IntList
. Даже в лучшем случае я могу обернуть реализацию Value
и Scan
как независимые функции, но все равно придется писать подписи для Scan
и Value
в IntList
. Есть какие-нибудь предложения, чтобы определить IntList
так же просто, как User
?
Комментарии:
1. Типы структур-это единственные конкретные типы, в которые допускается встраивание. Поскольку
IntList
это не тип структуры, вы не можете встроитьCustomJSONType
в нее a, как вы это сделали дляUser
.2. Чего вы пытаетесь достичь с
Scan
Value
помощью реализаций и для пустого типа структуры? Если вы ожидаетеCustomJSONType
«наследовать» поля структуры, в которую она встроена, вы должны знать, что это не то, что делает встраивание. В Go нет расширения типа.3.В принципе, вы должны явно определить
Scan
иValue
для обоих типов —IntList
и.User
ЭтоCustomJSONType
бесполезно, все, что он делает, это удовлетворяет интерфейсу, но реализация ничего не делает, такt
как в обоих методах есть пустая структура или указатель на пустую структуру.4. @mkopriva спасибо! Я не тестировал свой код во время выполнения.
5. @mkopriva Вы можете подделать расширение метода в Go, внедрив пустую структуру значений в качестве первого элемента с помощью метода с приемником указателя, в котором вы используете
unsafe.Pointer
для изменения типа приемника на то, в что встроена ваша структура. По крайней мере, до Go 2: github.com/golang/go/issues/18617 Не рекомендуется, но это работает.
Ответ №1:
В голанге нет понятия «наследовать», а есть только комбинация. Не нравится обычный язык ООП, структура CustomJSONType
не может получить доступ к данным из IntList
и User
, поэтому метод 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:
Не уверен, правильно ли я вас понял. Но вы можете объединить несколько типов, включая массив int, без создания структуры. Они остаются типом и доступны в функциях. Но объединение типов требует структуры, поэтому вы не можете напрямую использовать адресацию массива.
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