Golang返回接口

Let say we want to extend Error() function on error interface. We can simply create a struct derived from string implementing the Error() method. For example:

type NewUser struct {
    Email           string
    Password        string
}
type ErrMissingField string

func (e ErrMissingField) Error() string {
    return string(e) + " is required"
}

func (u *NewUser) OK() error {
    if len(u.Email) == 0 {
        return ErrMissingField("email")
    }
    if len(u.Password) == 0 {
        return ErrMissingField("password")
    }
    return nil
}

Above code will return either email is required or password is required.

But, if I create my own interface, let say ResponseError, like this:

type ResponseError interface {
    ErrorMsg() string
}

type CustomErr string

func (c CustomErr) ErrorMsg() string {
    return "[Error] " + string(c)
}
func (u *NewUser) NewOK() ResponseError {
    if len(u.Email) == 0 {
        return CustomErr("Email required!")
    }
    if len(u.Password) == 0 {
        return CustomErr("Password Required!")
    }
    return nil
}

It won't print the method implementation I wrote with [Error]. It just prints the string I passed into the struct Email required! or Password Required!.

How to work on this?

If you are using fmt to print, then from https://golang.org/pkg/fmt

  1. If an operand implements the error interface, the Error method will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any).

  2. If an operand implements method String() string, that method will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any)

That's why when you implement Error interface, it prints by invoking Error() function. If you want custom output for other interface like ResponseError implement String() method.

package main

import (
    "fmt"
)

type NewUser struct {
    Email           string
    Password        string
}

type ResponseError interface {
    ErrMsg()
    String() string
}

type CustomErr string

func (c CustomErr) String() string {
    return "[Error] " + string(c)
}

func (c CustomErr) ErrMsg() {}

func (u *NewUser) NewOK() ResponseError {
    if len(u.Email) == 0 {
        return CustomErr("Email required!")
    }
    if len(u.Password) == 0 {
        return CustomErr("Password Required!")
    }
    return nil
}

func main() {
    u := &NewUser{}
    fmt.Println(u.NewOK())
}

Go playground: https://play.golang.org/p/khAAtLodEND

Go treats types that implement error differently when printing. Your interface ResponseError does not implement error through adding Error() string.

To visualize what I'm talking about see the following example using error interface:

type NewUser struct {
    Email    string
    Password string
}

type ResponseError interface {
    error
    ErrorMsg() string
}

type CustomErr string

func (c CustomErr) ErrorMsg() string {
    return "[Error] " + string(c)
}

func (c CustomErr) Error() string {
    return c.ErrorMsg()
}

func (u *NewUser) NewOK() ResponseError {
    if len(u.Email) == 0 {
        return CustomErr("Email required!")
    }
    if len(u.Password) == 0 {
        return CustomErr("Password Required!")
    }
    return nil
}

func main() {
    user := NewUser{}
    fmt.Printf("Using %%s: %s
", user.NewOK())
    fmt.Printf("Using %%v: %v
", user.NewOK())
    fmt.Printf("Using %%v and call function ErrorMsg: %v
", user.NewOK().ErrorMsg())
    fmt.Printf("Using %%s and call function ErrorMsg: %s
", user.NewOK().ErrorMsg())
}

This will print the following:

Using %s: [Error] Email required!
Using %v: [Error] Email required!
Using %v and call function ErrorMsg: [Error] Email required!
Using %s and call function ErrorMsg: [Error] Email required!

However without error interface:

type NewUser struct {
    Email    string
    Password string
}

type ResponseError interface {
    ErrorMsg() string
}

type CustomErr string

func (c CustomErr) ErrorMsg() string {
    return "[Error] " + string(c)
}


func (u *NewUser) NewOK() ResponseError {
    if len(u.Email) == 0 {
        return CustomErr("Email required!")
    }
    if len(u.Password) == 0 {
        return CustomErr("Password Required!")
    }
    return nil
}

func main() {
    user := NewUser{}
    fmt.Printf("Using %%s: %s
", user.NewOK())
    fmt.Printf("Using %%v: %v
", user.NewOK())
    fmt.Printf("Using %%v and call function ErrorMsg: %v
", user.NewOK().ErrorMsg())
    fmt.Printf("Using %%s and call function ErrorMsg: %s
", user.NewOK().ErrorMsg())
}

The output is :

Using %s: Email required!
Using %v: Email required!
Using %v and call function ErrorMsg: [Error] Email required!
Using %s and call function ErrorMsg: [Error] Email required!