golang的fmt包String(),Error(),Format(),GoString()的接口实现

栏目: Go · 发布时间: 6年前

内容简介:golang的接口使用非常广泛,几乎每一个包都会用到接口,fmt包的使用率最多之一。在实际开发中,要定义结构体的标准输出用String(),定义标准错误输出Error(),定义格式化输出Format(),还有比较特殊的GoString()。接下来描述接口的使用方式,使用场景,还有注意的地方。使用起来比较简单,只要结构体里面有

golang的接口使用非常广泛,几乎每一个包都会用到接口,fmt包的使用率最多之一。在实际开发中,要定义结构体的标准输出用String(),定义标准错误输出Error(),定义格式化输出Format(),还有比较特殊的GoString()。接下来描述接口的使用方式,使用场景,还有注意的地方。

String()

type TestString struct {}
func (t TestString) String() string {
	return "我是String"
}
func main() {
    fmt.Println(TestString{})
}
复制代码
我是String
复制代码

使用起来比较简单,只要结构体里面有 String() string 就可以输出。

fmt 包里面会判断有没有 fmt.Stringer 的接口,然后再调用。

通常用于结构体的默认输出,例如:

type Student struct {
	number int
 	realname string
	age int
}
func main() {
	stu := &Student{
		number: 1,
		realname: "王小明",
		age: 18,
	}
	fmt.Println(stu)
}
复制代码
&{1 王小明 18}
复制代码

改成:

type Student struct {
	number int
 	realname string
	age int
}
func (t *Student) String() string {
	return fmt.Sprintf("学号: %d\n真实姓名: %s\n年龄: %d\n", t.number, t.realname, t.age)
}
func main() {
	stu := &Student{
		number: 1,
		realname: "王小明",
		age: 18,
	}
	fmt.Println(stu)
}
复制代码
学号: 1
真实姓名: 王小明
年龄: 18
复制代码

瞬间感觉高大上了吧!!

Error

type TestError struct {}
func (t TestError) Error() string {
	return "我是Error"
}
func main() {
    fmt.Println(TestString{})
}
复制代码
我是Error
复制代码

实际上使用方式跟 String() 一样,但是设计代码时不能互相替换实现。

最常用的用法是独立封装 type XXXError struct{} ,在文章最尾会揣摸一下为什么要这样用。

Format

type TestFormat struct {}
func (t TestFormat) Format(s fmt.State, c rune) {
	switch c {
	case 'c':
		switch {
		case s.Flag('+'):
			fmt.Printf("我是+c\n")
		default:
			fmt.Fprint(s, "我是c\n")
		}
	default:
		fmt.Print("我是Format")
	}
}
func main() {
    t := TestFormat{}
    fmt.Println(t)
    fmt.Printf("%c\n", t)
    fmt.Printf("%+c\n", t)
    fmt.Printf("%s\n", t)
}
复制代码
我是Format
我是c
我是+c
我是Format
复制代码

fmt.Println 也会调用Format的接口,所以 String() Format() 不能同一个结构体里面。 通常使用跟 Error() 类似,可以参考一下 github.com/pkg/errors 里的 stack.gofunc (f Frame) Format(s fmt.State, verb rune)

GoString

type TestGoString struct {}
func (t TestGoString) GoString() string {
	return "我是GoString"
}
func main() {
    t := TestGoString{}
    fmt.Println(TestGoString{})
    fmt.Printf("%s %#v\n", t, t)
}
复制代码
{}
{} 我是GoString
复制代码

如上所示 fmt.Println 并没调用GoString方法,只能通过格式化 %# +标记输出。

在没有实现接口的情况下,通常用来输出默认相应值,如下:

func main() {
	var i uint = 18
	// 输出十六进制
	fmt.Printf("%x\n", i)
	fmt.Printf("%#x\n", i)
}
复制代码
12
0x12
复制代码

注意事项

fmt/print.gopp.handleMethods(verb rune) (handled bool)

func (p *pp) handleMethods(verb rune) (handled bool) {
	...
	// 判断Formatter
	if formatter, ok := p.arg.(Formatter); ok {
	    ...
	    formatter.Format(p, verb)
	    return
	}
    
        // 判断是否含有#标识符
	if p.fmt.sharpV {
	        // 判断GoStriner
		if stringer, ok := p.arg.(GoStringer); ok {
                        ...
			p.fmt.fmtS(stringer.GoString())
			return
		}
	} else {
		switch verb {
		case 'v', 's', 'x', 'X', 'q':
			switch v := p.arg.(type) {
			// 符合error接口
			case error:
                                ...
				p.fmtString(v.Error(), verb)
				return
                        // 符合Stringer接口
			case Stringer:
                                ...
				p.fmtString(v.String(), verb)
				return
			}
		}
	}
	return false
}

复制代码

Format -> (#)GoString -> ((v,s,x,X,q)Error -> String) 源码四个接口都在handlerMethods方法调用控制,都不是互相独立,根据优先顺序调用。所以接口的设计,尽可能独立封装,避免混淆。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Where Wizards Stay Up Late

Where Wizards Stay Up Late

Katie Hafner / Simon & Schuster / 1998-1-21 / USD 16.00

Twenty five years ago, it didn't exist. Today, twenty million people worldwide are surfing the Net. "Where Wizards Stay Up Late" is the exciting story of the pioneers responsible for creating the most......一起来看看 《Where Wizards Stay Up Late》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

随机密码生成器
随机密码生成器

多种字符组合密码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具