第三十七:定义错误类型

任意类型添加方法

在Go语言中,接收者的类型可以是任何类型,不仅仅是结构体,任何类型都可以拥有方法。 举个例子,我们基于内置的int类型使用type关键字可以定义新的自定义类型,然后为我们的自定义类型添加方法。

复制代码
//MyInt 将int定义为自定义MyInt类型
type MyInt int

//SayHello 为MyInt添加一个SayHello的方法
func (m MyInt) SayHello() {
	fmt.Println("Hello, 我是一个int。")
}
func main() {
	var m1 MyInt
	m1.SayHello() //Hello, 我是一个int。
	m1 = 100
	fmt.Printf("%#v  %T\n", m1, m1) //100  main.MyInt
}
Go 复制代码
type Status int8

const (
	Running Status = 1
	Warning Status = 2
)


// 将方法名改为 MarshalJSON 即可让 json 包自动调用
func (s Status) MarshalJSON() (data []byte, err error) {
	var str string
	switch s {
	case Running:
		str = "运行中"
	case Warning:
		str = "警告"
	default:
		str = "未知"
	}
	return json.Marshal(str)
}

// 5. 添加反序列化支持
// 如果需要从 JSON 反序列化
func (s *Status) UnmarshalJSON(data []byte) error {
	var str string
	if err := json.Unmarshal(data, &str); err != nil {
		return err
	}
	
	switch str {
	case "运行中":
		*s = Running
	case "警告":
		*s = Warning
	default:
		return fmt.Errorf("未知状态: %s", str)
	}
	return nil
}


// 这样 json.Marshal(user) 就会自动使用这个方法

type User struct {
	ID     int64
	Name   string `gorm:"size:32"`
	Status Status `json:"status"`
}

最后调用:Marshal

// 调用 json.Marshal 时,会自动调用 MarshalJSON 方法
	user := User{
		ID:     1,
		Name:   "李四",
		Status: Warning,
	}
	data, err = json.Marshal(user)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(data)) // 输出: {"ID":1,"Name":"李四","status":"警告"}


// 反序列化调用示例 Unmarshal
func unmarshalExample() {
    jsonStr := `{"ID":1,"Name":"张三","status":"运行中"}`
    var user User
    if err := json.Unmarshal([]byte(jsonStr), &user); err != nil {
        panic(err)
    }
    fmt.Printf("用户状态: %d\n", user.Status) // 输出: 用户状态: 1
}

// 单独调用一种方法:

// 直接调用 MarshalJSON 方法
	runningStatus := Running
	data, err := runningStatus.MarshalJSON()
	if err != nil {
		panic(err)
	}
	fmt.Println("Running OldName:", string(data)) // 输出: "运行中"

扩展建议:可以考虑为 Status 类型添加字符串方法,便于直接输出:

Go 复制代码
type Status int8

const (
	Running Status = 1
	Warning Status = 2
)

user := User{
        Name:   "赵六",
        Status: Warning,
    }

func (s Status) String() string {
    switch s {
    case Running:
        return "运行中"
    case Warning:
        return "警告"
    default:
        return "未知"
    }
}

// 使用示例
func stringExample() {
    user := User{Status: Running}
    fmt.Println(user.Status.String()) // 输出: 运行中
}
相关推荐
紧跟先前的步伐1 天前
Go AI Agent 实战 22|完善 Agent 执行循环:从工具调用到最终回答
人工智能·ai·golang
后台模板学习1 天前
Go Web开发中任务调度框架的源码解析与高可用实现方案
开发语言·后端·golang
FungLeo1 天前
成为全栈·Go 后端篇·分类树与标签关系:目录变更为何需要协调
golang·go·gorm·数据库事务·分类树·成为全栈
fly-iot1 天前
【FDE知识库】(1):AI 编程时代开发语言选型分析,云使用go,企业用java,算法python,底层c
开发语言·人工智能·golang
FungLeo1 天前
成为全栈·Go 后端篇·文章查询与展示投影:安全分页、排序和软删除
golang·go·gorm·分页查询·成为全栈·sql安全
紧跟先前的步伐2 天前
Go AI Agent 实战 24|工具系统工程化收尾与阶段验收
人工智能·ai·golang·1024程序员节
日日大王学编程2 天前
#Feed 流项目复盘:Redis 时间线缓存与 Outbox 消息可靠性设计
golang·1024程序员节
北冥you鱼2 天前
Go 语言 CRUD 实战:从接口设计到真实业务场景
开发语言·后端·golang
利威尔xu2 天前
Go IM 源码实战(11):token 只是个 HASH,多端互踢的顺序错了就踢错人
后端·微服务·面试·架构·golang
microrain2 天前
SagooIoT 把协议解析和消息通知都放进了独立进程
物联网·golang·插件·sagooiot