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方法调用控制,都不是互相独立,根据优先顺序调用。所以接口的设计,尽可能独立封装,避免混淆。


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

查看所有标签

猜你喜欢:

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

Web性能优化

Web性能优化

Patrick Killelea 谢 / 谢文亮 / 清华大学出版社 / 2003-11-01 / 49.00元

本书讲述如何将Web性能调至最佳状态。书中不仅谈到了Web服务器软件的优化,而且还涉及到如何流水化处理Web内容,如何从浏览器端着手优化性能,如何调校客户端和服务器的硬件,以及如何最大限度地使用网络本身的特性。 书中的内容涉及到影响性能好坏的本质,并为得到立竿见影的效果提供了具体建议。本书向您娓娓道出评价计算性能高低的准则,并在后半部分讲述从客户端、网络直到服务器这一链条中每个环节的薄弱之一起来看看 《Web性能优化》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具