使用自定义的Scan函数将Unmarshal到枚举类型中

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

Unmarshal to Enum type using a custom Scan func

问题

我正在尝试解析一个Gender类型,它是一个枚举类型,在底层只是一个int64(我不想使用该类型的任何字符串表示)。

问题是Gender的值没有被正确处理,我总是得到0。

我可能漏掉了一些东西,但我看不到...

非常感谢。

https://go.dev/play/p/bfnI_ESpzJY

package main

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

type Person struct {
	name   string `json:"name"`
	gender Gender `json:"gender"`
}

type Gender int64

const (
	Undefined Gender = iota
	Male
	Female
	NonBinary
)

func (g *Gender) Scan(v interface{}) error {
	if v == nil {
		*g = Gender(Undefined)
		return nil
	}

	ns := sql.NullInt64{}
	if err := ns.Scan(v); err != nil {
		return err
	}

	if !ns.Valid {
		return fmt.Errorf("Gender.Scan: column is not nullable")
	}

	if ns.Int64 > 3 {
		return fmt.Errorf("Gender.Scan: gender value > 3")
	}
	*g = genderFromInt64(ns.Int64) // tried Gender(ns.Int64) without success
	return nil
}

// tried genderFromInt64(i int64) instead of Gender(ns.Int64) without success
func genderFromInt64(i int64) Gender {
	switch i {
	case 0:
		return Undefined
	case 1:
		return Male
	case 2:
		return Female
	case 3:
		return NonBinary
	default:
		return Female
	}
}

// Value() is not used yet
func (g Gender) Value() (driver.Value, error) {
	return int64(g), nil
}

func (g Gender) String() string {
	return [...]string{"Undefined", "Male", "Female", "Non-binary"}[g]
}

func main() {
	var person Person
	jsonPerson := `{"name": "John", "gender": 2}`

	json.Unmarshal([]byte(jsonPerson), &person)
	fmt.Printf("%+v", person)
}

英文:

I'm trying to unmarshall a Gender type that is an Enumeration that is just int64 under the hood (I don't want to use any string representation of this type).

Problem is that the Gender value is not handled properly, I always ended with 0.

I'm missing something but I don't see it...

Thank you so much.

https://go.dev/play/p/bfnI_ESpzJY

package main

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

type Person struct {
	name   string `json:"name"`
	gender Gender `json:"gender"`
}

type Gender int64

const (
	Undefined Gender = iota
	Male
	Female
	NonBinary
)

func (g *Gender) Scan(v interface{}) error {
	if v == nil {
		*g = Gender(Undefined)
		return nil
	}

	ns := sql.NullInt64{}
	if err := ns.Scan(v); err != nil {
		return err
	}

	if !ns.Valid {
		return fmt.Errorf("Gender.Scan: column is not nullable")
	}

	if ns.Int64 > 3 {
		return fmt.Errorf("Gender.Scan: gender value > 3")
	}
	*g = genderFromInt64(ns.Int64) // tried Gender(ns.Int64) without success
	return nil
}

// tried genderFromInt64(i int64) instead of Gender(ns.Int64) without success
func genderFromInt64(i int64) Gender {
	switch i {
	case 0:
		return Undefined
	case 1:
		return Male
	case 2:
		return Female
	case 3:
		return NonBinary
	default:
		return Female
	}
}

// Value() is not used yet
func (g Gender) Value() (driver.Value, error) {
	return int64(g), nil
}

func (g Gender) String() string {
	return [...]string{"Undefined", "Male", "Female", "Non-binary"}[g]
}

func main() {
	var person Person
	jsonPerson := `{"name": "John", "gender": 2}`

	json.Unmarshal([]byte(jsonPerson), &person)
	fmt.Printf("%+v", person)
}

答案1

得分: 3

在你的代码中,我想指出两件事情(已经被@mkopriva提到了):

  1. Person的字段是未导出的,对于未导出的字段,无法在解组方法中访问。你可以使用go vet命令来帮助你防止这类错误。

  2. 你已经实现了Stringer接口,将Gender值从枚举转换为字符串。如果你不想将这个类型表示为字符串,你可以注释掉String方法。

    func (g Gender) String() string {
    return [...]string{"Undefined", "Male", "Female", "Non-binary"}[g]
    }
    

https://go.dev/play/p/C1ZUv_fES0k

英文:

In your code, I want to point out 2 things (which is already mention by @mkopriva)

  1. Person's fields are unexported and are not visible to unmarshal methods. You can use go vet command it will help you to prevent these kinds of errors

  2. You have implemented the Stringer interface which converts Gender value from enum to string. if you don't want to represent this type as a string you can comment String method

    func (g Gender) String() string {
    return [...]string{"Undefined", "Male", "Female", "Non-binary"}[g]
    }

https://go.dev/play/p/C1ZUv_fES0k

huangapple
  • 本文由 发表于 2022年7月2日 23:02:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/72840085.html
匿名

发表评论

匿名网友

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

确定