从StatusCmd的源码分析返回值

当我们在执行一个函数时,可能会有一个指针形式的返回值,我们不能够直接使用。
而是需要使用此指针的结构体定义的众多方法去将内容返回出来。
函数返回的实质上是*redis.StatusCmd的指针,该类型有以下方法:

  • Name()
  • Args()
  • Err()
  • String()
  • Val()
  • Result()

Result()

例子1:

//type string connect Redis
func (this *RedisStringAPI) Open(Addr, Password string, DB int) *redis.Client {
    //连接
    client := redis.NewClient(&redis.Options{
        Addr:     Addr,
        Password: Password, // no password set
        DB:       DB,       // use default DB
    })
    pong, err := client.Ping().Result()
    fmt.Println(pong, err)
    return client
}

连接Redis数据库时,我们可以用type Client下的Ping()函数测试一下是否连接成功。
但注意.Result()是必不可少的,否则会出现以下报错:

assignment mismatch: 2 variables but 1 values

这是因为Ping()并非返回了一个string数据类型,我们可以看下Client.Ping()的源码:

func (c cmdable) Ping() *StatusCmd {
    cmd := NewStatusCmd("ping")
    _ = c(cmd)
    return cmd
}

可以发现Ping()函数返回的是StatusCmd指针。
我们再看一下
StatusCmd的源码:(此源码位于srcgithub.comgo-redisrediscommand.go)

type StatusCmd struct {
    baseCmd

    val string
}

var _ Cmder = (*StatusCmd)(nil)

func NewStatusCmd(args ...interface{}) *StatusCmd {
    return &StatusCmd{
        baseCmd: baseCmd{args: args},
    }
}

func (cmd *StatusCmd) Val() string {
    return cmd.val
}

func (cmd *StatusCmd) Result() (string, error) {
    return cmd.val, cmd.err
}

func (cmd *StatusCmd) String() string {
    return cmdString(cmd, cmd.val)
}

func (cmd *StatusCmd) readReply(rd *proto.Reader) error {
    cmd.val, cmd.err = rd.ReadString()
    return cmd.err
}

可以看到在StatusCmd下有一个Result()方法,可以返回一个string类型。
像是一些查询函数Get()、HGet()等都需要一个Result()函数,原因就是上边探讨的结果。

Err()

例子2:

//type string write
func (this *RedisStringAPI) SetString(client *redis.Client, key, value string, second int) {
    //在设置过期时间时,注意单位应该是 *time.Second(或其他单位),并用time.Duration()转换类型
    err := client.Set(key, value, time.Duration(second)*time.Second).Err()
    if err != nil {
        fmt.Println("Set string error:", err)
    }
    fmt.Println("Set successfully")
}

当我们向Redis写入数据时,可以使用Err()用作验证是否有误,但它不是必须的。

Client.Set()源码:

// Zero expiration means the key has no expiration time.
func (c cmdable) Set(key string, value interface{}, expiration time.Duration) *StatusCmd {
    args := make([]interface{}, 3, 4)
    args[0] = "set"
    args[1] = key
    args[2] = value
    if expiration > 0 {
        if usePrecise(expiration) {
            args = append(args, "px", formatMs(expiration))
        } else {
            args = append(args, "ex", formatSec(expiration))
        }
    }
    cmd := NewStatusCmd(args...)
    _ = c(cmd)
    return cmd
}

返回的也是StatusCmd,但要注意一下,Err()并不在StatusCmd里,而是在baseCmd,并且StatusCmd和baseCmd是包含关系。StatusCmd嵌套有baseCmd,看下StatusCmd的结构体结构:

type StatusCmd struct {
    baseCmd

    val string
}

再看下baseCmd的源码:

type baseCmd struct {
    args []interface{}
    err  error

    _readTimeout *time.Duration
}

var _ Cmder = (*Cmd)(nil)

func (cmd *baseCmd) Name() string {
    if len(cmd.args) == 0 {
        return ""
    }
    // Cmd name must be lower cased.
    return internal.ToLower(cmd.stringArg(0))
}

func (cmd *baseCmd) Args() []interface{} {
    return cmd.args
}

func (cmd *baseCmd) stringArg(pos int) string {
    if pos < 0 || pos >= len(cmd.args) {
        return ""
    }
    s, _ := cmd.args[pos].(string)
    return s
}

func (cmd *baseCmd) setErr(e error) {
    cmd.err = e
}

func (cmd *baseCmd) Err() error {
    return cmd.err
}

func (cmd *baseCmd) readTimeout() *time.Duration {
    return cmd._readTimeout
}

func (cmd *baseCmd) setReadTimeout(d time.Duration) {
    cmd._readTimeout = &d
}

调用Err()就返回了一个error类型的值。

Last modification:October 18th, 2019 at 04:30 pm
如果觉得我的文章对你有用,请随意赞赏