首页 > 其他分享 >golang中的nil接收器

golang中的nil接收器

时间:2022-10-29 23:05:39浏览次数:34  
标签:接收器 errors nil err CustomError golang func string



我们先看一个简单的例子,我们自定义一个错误,用来把多个错误放在一起输出:

type CustomError struct {
errors []string
}

func (c *CustomError) Add(err string) {
c.errors = append(c.errors, err)
}

func (c *CustomError) Error() string {
return strings.Join(c.errors, ";")
}

因为实现了​​Error() string​​方法,所以它实现了error接口。

现在我们要实现一个添加课件的功能,但是添加之前需要验证参数的合法性,所以我们创建了一个Validate方法,我们可能会这么写:

package main

import (
"errors"
"fmt"
"strings"
)

type CustomError struct {
errors []string
}

func (c *CustomError) Add(err error) {
c.errors = append(c.errors, err.Error())
}

func (c *CustomError) Error() string {
return strings.Join(c.errors, ";")
}

type Courseware struct {
Name string
Code string
}

func (c *Courseware) Validate() error {
var m *CustomError // 1
if c.Name == "" { // 2
m = &CustomError{}
m.Add(errors.New("课件名不能为空"))
}
if c.Code == "" { // 3
if m == nil {
m = &CustomError{}
}
m.Add(errors.New("课件编号不能为空"))
}

return m // 4
}

func main() {
m := Courseware{
Name: "多媒体课件",
Code: "CW330",
}
if err := m.Validate(); err != nil {
fmt.Println("valid err: ", err)
}
}

看上去好像一点问题都没有:

  1. 定义一个CustomError类型的指针
  2. 如果Name为空,初始化m,调用Add方法把错误添加到CustomError.errors
  3. 如果Code为空,如果m还没有初始化,先初始化,调用Add方法把错误添加到CustomError.errors
  4. 最后返回自定义错误

但是当我们执行上面的代码时,会发现结果并不是我们想要的:

go run 8.go
valid err: <nil>

我们发现居然走到了打印错误的判断里,但是打印出来的错误居然是一个​​nil​​。

在 Go 中,我们必须知道指针接收器可以为 nil。我们看一个简单的例子:

package main

import (
"fmt"
)

type Demo struct {
}

func (d *Demo) Print() string {
return "demo"
}

func main() {
var d *Demo
fmt.Println(d)
fmt.Println(d.Print())
}
go run 8.go
<nil>
demo

Demo被初始化为nil,但是这段代码可以正常运行。说明nil指针也可以作为接收器。

其实上面的Print方法等价于:

func Print(d *Demo) string {
return "demo"
}

因为将 nil 指针传递给函数是有效的。 所以使用 nil 指针作为接收器也是有效的。

我们继续回到上面的自定义错误。

m 被初始化为指针的零值:nil。 如果所有验证都通过,return 语句返回的结果不是 nil,而是一个 nil 指针。 因为 nil 指针是一个有效的接收器,所以将结果转换为error接口不会产生 nil 值。

所以我们虽然返回了一个nil指针,但是转换为error接口时并不是一个nil的接口(虽然是nil指针,但是是*CustomError类型,并实现了error)。

要解决这个问题,我们只要直接返回nil值,不返回nil的指针:

package main

import (
"errors"
"fmt"
"strings"
)

type CustomError struct {
errors []string
}

func (c *CustomError) Add(err error) {
c.errors = append(c.errors, err.Error())
}

func (c *CustomError) Error() string {
return strings.Join(c.errors, ";")
}

type Courseware struct {
Name string
Code string
}

func (c *Courseware) Validate() error {
var m *CustomError
if c.Name == "" {
m = &CustomError{}
m.Add(errors.New("课件名不能为空"))
}
if c.Code == "" {
if m == nil {
m = &CustomError{}
}
m.Add(errors.New("课件编号不能为空"))
}

// 这里如果m指针为nil,直接返回nil
if m == nil {
return nil
}

return m
}

func main() {
m := Courseware{
Name: "多媒体课件",
Code: "CW330",
}

if err := m.Validate(); err != nil {
fmt.Println("valid err: ", err)
}
}

或者我们直接返回*CustomError类型的错误:

package main

import (
"errors"
"fmt"
"strings"
)

type CustomError struct {
errors []string
}

func (c *CustomError) Add(err error) {
c.errors = append(c.errors, err.Error())
}

func (c *CustomError) Error() string {
return strings.Join(c.errors, ";")
}

type Courseware struct {
Name string
Code string
}

// 返回*CustomError
func (c *Courseware) Validate() *CustomError {
var m *CustomError
if c.Name == "" {
m = &CustomError{}
m.Add(errors.New("课件名不能为空"))
}
if c.Code == "" {
if m == nil {
m = &CustomError{}
}
m.Add(errors.New("课件编号不能为空"))
}

return m
}

func main() {
m := Courseware{
Name: "多媒体课件",
Code: "CW330",
}

if err := m.Validate(); err != nil {
fmt.Println("valid err: ", err)
}
}

但这并不是可取的,为了扩展我们实现了error接口,也需要返回error类型的错误。


标签:接收器,errors,nil,err,CustomError,golang,func,string
From: https://blog.51cto.com/u_13929949/5806573

相关文章

  • golang中的字符串
    0.1、索引​​https://waterflow.link/articles/1666449874974​​1、字符串编码在go中rune是一个unicode编码点。我们都知道UTF-8将字符编码为1-4个字节,比如我们常用的汉字......
  • Golang基础-函数
    一、引入函数提高代码的复用性,减少代码的冗余,提高代码的维护性为完成某一功能的程序指令(语句)的集合,称为函数基本语法:func函数名(形参列表)(返回值类型列表){执......
  • golang的interface
    golang的interface0.介绍接口是Go语言提供的数据类型之一,它把所有具有共性的方法(注意与函数区别开)定义在一起,任何其它类型只要一一实现这些方法的话,我们就称这个类型......
  • golang学习之路1-环境安装及Helloword
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档@目录Golang学习之路前言一、安装环境1.Golang安装2.GoLand安装二、第一个go程序HelloWord三、go命令......
  • golang学习之路2-基础认识(上)
    @目录前言一、变量定义1.变量2.数据类型二、自增自减三、指针1.使用指针&及*2.空指针3.指针完整代码四、不支持语法1.自增自减--i及++i2.不支持内存地址(指针)加减3.......
  • golang实现RSA2的签名与验签函数
    使用非对称加密算法,实现签名与验签packagetoolsimport("crypto""crypto/rand""crypto/rsa""crypto/sha256""crypto/x509""encoding/b......
  • golang 学习入门项目(超适合新手入门,新手进阶)
    过年的疫情,让我有了时间整理自己的博客。这篇是关于如何学习golang这门语言的。实例代码一分享到github点击获取源码 ​​github学习golang​​本项目是个gogin框架写的......
  • golang---恢复符号
    golang---恢复符号这样编译go程序,可以去除符号,加大逆向人员分析难度gobuild-ohello-ldflags'-s'hello.go不过符号并不是真的删掉了,可以通过一些脚本恢复回来for......
  • Golang基础-流程控制
    流程控制语句是用来控制程序中各语句执行顺序的语句,可以把语句组合成能完成一定功能的小逻辑模块控制语句分为三大类:顺序、选择、循环一、分支结构if分支结构单分支......
  • Golang Vue 后台框架 go-admin 从零开始企业级实战视频教程(33 个视频)
    GolangVue后台框架go-admin从零开始企业级实战视频教程(33个视频)Golang作为后端应该会成为未来几年的主要趋势之一,Vue又是用得最多的框架,go-admin是一个很成熟的后......