go Print 和 反射
2022/3/31 23:50:33
本文主要是介绍go Print 和 反射,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
0. 前言
在 小白学标准库之反射 reflect 篇中介绍了反射的三大法则。但并未给出具体示例介绍反射,感觉还是少了点什么。这里进一步通过fmt.Println
源码,查看反射如何使用的,算是对前文的补充。由于文章已经够长了,为方便观看,新开一篇介绍,当然内容不会太多。
1. fmt.Println 函数
go 中 Print 系列函数(fmt.Println, fmt.Printf...) 可以打印任意类型,这是怎么做到的呢?结合前面学习我们知道通过反射能够在运行时获取类型值。
查看 fmt.Println
函数实现:
func Println(a ...interface{}) (n int, err error) { return Fprintln(os.Stdout, a...) } func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { p := newPrinter() p.doPrintln(a) n, err = w.Write(p.buf) p.free() return }
Println 调用 Fprintln 函数,Fprintln 首先 new 一个 Printer p,接着通过 p 执行 doPrintln:
func (p *pp) doPrintln(a []interface{}) { for argNum, arg := range a { if argNum > 0 { p.buf.writeByte(' ') } p.printArg(arg, 'v') } p.buf.writeByte('\n') }
doPrintln 首先解析参数,接着处理参数。重点放在 printArg 这里:
// Some types can be done without reflection. switch f := arg.(type) { case bool: p.fmtBool(f, verb) case float32: p.fmtFloat(float64(f), 32, verb) ... case reflect.Value: // Handle extractable values with special methods // since printValue does not handle them at depth 0. if f.IsValid() && f.CanInterface() { p.arg = f.Interface() if p.handleMethods(verb) { return } } p.printValue(f, verb, 0) default: // If the type is not simple, it might have methods. if !p.handleMethods(verb) { // Need to use reflection, since the type had no // interface methods that could be used for formatting. p.printValue(reflect.ValueOf(f), verb, 0) } }
doPrintln 函数内容较多,这里摘出重要部分进行介绍。
首先,通过类型断言判断接口值,如果判断不出来则走到 default 分支(这也和 小白学标准库之反射 开篇介绍的对应,即类型断言的表示能力有限,更复杂的表达能力需要通过反射),通过反射机制反射接口值。
如当打印结构体时,分支判断会走到 default,通过反射获取结构体的值:
func main() { a := person{ name: "lubanseven", } fmt.Println(a) }
这里有几点注意的是:
p.printValue
函数是对反射代码在运行时的处理,相比于直接处理,更加复杂,读写都不容易。这也是在静态语言中使用动态特性付出的成本。关于反射代码在运行时的写法可参考 这里- 不管是 小白学标准库之反射 reflect 还是这篇文章都没有介绍汇编,因为汇编是在编译阶段确定的,而反射的实现是在运行时,通过汇编能看到的是 CALL xxx.Println(SB),无法看到具体运行时的实现。
这篇关于go Print 和 反射的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-15SendGrid 的 Go 客户端库怎么实现同时向多个邮箱发送邮件?-icode9专业技术文章分享
- 2024-11-15SendGrid 的 Go 客户端库怎么设置header 和 标签tag 呢?-icode9专业技术文章分享
- 2024-11-12Cargo deny安装指路
- 2024-11-02MongoDB项目实战:从入门到初级应用
- 2024-11-01随时随地一键转录,Google Cloud 新模型 Chirp 2 让语音识别更上一层楼
- 2024-10-25Google Cloud动手实验详解:如何在Cloud Run上开发无服务器应用
- 2024-10-24AI ?先驱齐聚 BAAI 2024,发布大规模语言、多模态、具身、生物计算以及 FlagOpen 2.0 等 AI 模型创新成果。
- 2024-10-20goland工具下,如修改一个项目的标准库SDK的版本-icode9专业技术文章分享
- 2024-10-17Go学习:初学者的简单教程
- 2024-10-17Go学习:新手入门完全指南