在GoLang中使用嵌套结构打印struct的奇怪行为

Posted Golang语言社区

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在GoLang中使用嵌套结构打印struct的奇怪行为相关的知识,希望对你有一定的参考价值。

Normally when trying to print a struct , we would use %v to show all data of the struct. It will print the default format for each field in the struct.

%v	the value in a default format
	when printing structs, the plus flag (%+v) adds field names

But recently we observed a strange behavior when printing a struct with nested struct which has a String() string implemented, the %v format prints an 'unexpected' output per our understanding.  

Let's see the example snippet first.

package mainimport (
  "fmt")type Inner struct {}type A struct {
    Inner
    FieldA string}func (i Inner) String() string {
    return "anything"}func main() {
    myA := A{FieldA: "A"}
    fmt.Printf("%v", myA)}

 We expect the output to be

{anything A}

But the actual result is

anything

This doesn't make sense, right? It seems FieldA is ignored if the String() string is implemented for Inner struct type.

Per our understanding, the struct A type has two fields: Inner and FieldA, when printing the values, it would loop through the fields and print using their default format. So Inner should call its String() while FieldA will print its string value. However, the above output makes us doubt our understanding.

After a closer look at the docs, it has below rules.

If the format (which is implicitly %v for Println etc.) is valid for a string (%s %q %v %x %X), the following two rules apply:

  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).

Since Inner is an operand and it implements the String() string method which is considered as a Stringer interface, so it is called when printing. This explains the output we actually see.  Below is actually the part of source code in Go.

switch verb {case 'v', 's', 'x', 'X', 'q':
	// Is it an error or Stringer?
	// The duplication in the bodies is necessary:
	// setting handled and deferring catchPanic
	// must happen before calling the method.
	switch v := p.arg.(type) {
	case error:
		handled = true
		defer p.catchPanic(p.arg, verb)
		p.fmtString(v.Error(), verb)
		return

	case Stringer:
		handled = true
		defer p.catchPanic(p.arg, verb)
		p.fmtString(v.String(), verb)
		return
	}}

 Now what if we have two nested structs in A and both of them have String() string implemented?

package mainimport (
  "fmt")type Inner struct {}type InnerAgain struct {}type A struct {
    Inner
    InnerAgain
    FieldA string}func (i Inner) String() string {
    return "anything"}func (i InnerAgain) String() string {
    return "nothing"}func main() {
    myA := A{FieldA: "A"}
    fmt.Printf("%v", myA)}

 The output is what we originally expected

{anything nothing A}

The reason for above output is that it is ambiguous which String() to invoke so it will fallback to loop through all fields and get their value in default format.

Please be careful about the above behavior Go provides so that you would not miss out some important data when printing struct in log with %v format.

One final thought about above behavior. Is the rule #5 reasonable in the first place? 


版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢。

在GoLang中使用嵌套结构打印struct的奇怪行为

Golang语言社区

ID:Golangweb

 www.GolangWeb.com

游戏服务器架构丨分布式技术丨大数据丨游戏算法学习


以上是关于在GoLang中使用嵌套结构打印struct的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章

golang结构体组合与“多态” 2021-08-06

Golang 面向对象编程

Golang之struct

[]map[string]struct 的 Golang 赋值错误

golang 入门之struct继承,嵌套

golang超级mapper包 - coven