golang how to print struct value with pointer

huangapple go评论103阅读模式
英文:

golang how to print struct value with pointer

问题

package main

import "fmt"

type A struct {
    a int32
    B *B
}
type B struct {
    b int32
}

func main() {
    a := &A{
        a: 1,
        B: &B{
            b: 2,
        },
    }
    fmt.Printf("v ==== %+v \n", a)
}


//ret: v ==== &{a:1 B:0xc42000e204}
//??? how to print B's content but not pointer
package main

import "fmt"

type A struct {
    a int32
    B *B
}
type B struct {
    b int32
}

func main() {
    a := &A{
        a: 1,
        B: &B{
            b: 2,
        },
    }
    fmt.Printf("v ==== %+v \n", a)
}
package main

import "fmt"

type A struct {
    a int32
    B *B
}
type B struct {
    b int32
}

func main() {
    a := &A{
        a: 1,
        B: &B{
            b: 2,
        },
    }
    fmt.Printf("v ==== %+v \n", a)
}
package main

import "fmt"

type A struct {
    a int32
    B *B
}
type B struct {
    b int32
}

func main() {
    a := &A{
        a: 1,
        B: &B{
            b: 2,
        },
    }
    fmt.Printf("v ==== %+v \n", a)
}
package main

import "fmt"

type A struct {
    a int32
    B *B
}
type B struct {
    b int32
}

func main() {
    a := &A{
        a: 1,
        B: &B{
            b: 2,
        },
    }
    fmt.Printf("v ==== %+v \n", a)
}
package main

import "fmt"

type A struct {
    a int32
    B *B
}
type B struct {
    b int32
}

func main() {
    a := &A{
        a: 1,
        B: &B{
            b: 2,
        },
    }
    fmt.Printf("v ==== %+v \n", a)
}
package main

import "fmt"

type A struct {
    a int32
    B *B
}
type B struct {
    b int32
}

func main() {
    a := &A{
        a: 1,
        B: &B{
            b: 2,
        },
    }
    fmt.Printf("v ==== %+v \n", a)
}
package main

import "fmt"

type A struct {
    a int32
    B *B
}
type B struct {
    b int32
}

func main() {
    a := &A{
        a: 1,
        B: &B{
            b: 2,
        },
    }
    fmt.Printf("v ==== %+v \n", a)
}
package main

import "fmt"

type A struct {
    a int32
    B *B
}
type B struct {
    b int32
}

func main() {
    a := &A{
        a: 1,
        B: &B{
            b: 2,
        },
    }
    fmt.Printf("v ==== %+v \n", a)
}
package main

import "fmt"

type A struct {
    a int32
    B *B
}
type B struct {
    b int32
}

func main() {
    a := &A{
        a: 1,
        B: &B{
            b: 2,
        },
    }
    fmt.Printf("v ==== %+v \n", a)
}
package main

import "fmt"

type A struct {
    a int32
    B *B
}
type B struct {
    b int32
}

func main() {
    a := &A{
        a: 1,
        B: &B{
            b: 2,
        },
    }
    fmt.Printf("v ==== %+v \n", a)
}
package main

import "fmt"

type A struct {
    a int32
    B *B
}
type B struct {
    b int32
}

func main() {
    a := &A{
        a: 1,
        B: &B{
            b: 2,
        },
    }
    fmt.Printf("v ==== %+v \n", a)
}
英文:
package main

import "fmt"

type A struct {
	a int32
	B *B
}
type B struct {
	b int32
}

func main() {
	a := &A{
		a: 1,
		B: &B{
			b: 2,
		},
	}
	fmt.Printf("v ==== %+v \n", a)
}


//ret: v ==== &{a:1 B:0xc42000e204}
//??? how to print B's content but not pointer

答案1

得分: 17

基本上,你必须自己做。有两种方法可以做到这一点。要么只是按照你想要的方式打印,要么通过为结构体实现Stringer接口来添加一个func String() string,当你使用格式%v时会调用该函数。你也可以在格式中引用结构体中的每个值。

实现Stringer接口是始终获得你想要的内容的最可靠的方法。而且,你只需要对每个结构体执行一次,而不是每次打印时都执行。

以下是示例代码:

package main

import "fmt"

type A struct {
    a int32
    B *B
}

type B struct{ b int32 }

func (aa *A) String() string {
    return fmt.Sprintf("A{a:%d, B:%v}", aa.a, aa.B)
}

func (bb *B) String() string {
    return fmt.Sprintf("B{b:%d}", bb.b)
}

func main() {
    a := &A{a: 1, B: &B{b: 2}}
    
    // 使用Stringer接口
    fmt.Printf("v ==== %v \n", a)
    
    // 或者按照你想要的方式自己打印
    fmt.Printf("v ==== A{a:%d, B:B{b:%d}}\n", a.a, a.B.b)
    
    // 或者直接引用结构体中的结构体值
    // 但这可能会变得非常深层
    fmt.Printf("v ==== A{a:%d, B:%v}", a.a, a.B)
}

你可以在这里运行这段代码:https://play.golang.org/p/PKLcPFCqOe

英文:

Basically, you have to do it yourself. There are two ways to do this. Either just print the thing how you want, or implement the Stringer interface for the struct by adding a func String() string, which gets called when you use the format %v. You could also reference each value in the format which is a struct.

Implementing the Stringer interface is the surest way to always get what you want. And you only have to do it once per struct, instead of per format string when you print.

https://play.golang.org/p/PKLcPFCqOe

package main

import "fmt"

type A struct {
	a int32
	B *B
}

type B struct{ b int32 }

func (aa *A) String() string {
	return fmt.Sprintf("A{a:%d, B:%v}",aa.a,aa.B)
}

func (bb *B) String() string {
	return fmt.Sprintf("B{b:%d}",bb.b)
}

func main() {
	a := &A{a: 1, B: &B{b: 2}}
	
	// using the Stringer interface
	fmt.Printf("v ==== %v \n", a)
	
	// or just print it yourself however you want.
	fmt.Printf("v ==== A{a:%d, B:B{b:%d}}\n", a.a, a.B.b)
	
	// or just reference the values in the struct that are structs themselves
	// but this can get really deep
	fmt.Printf("v ==== A{a:%d, B:%v}", a.a, a.B)
}

答案2

得分: 11

当你处理较大的结构体时,编写大量自定义的字符串函数会变得很麻烦。Goconvey目前使用以下项目来显示任意大小的结构体的差异和预期/实际输出:https://github.com/luci/go-render/blob/master/render/render.go#L51。它包括显示指针值。

如果你需要将输出作为可重用的代码(类似于fmt.Printf("%#v", a),但包括指针值),我有一个修改过的上述项目的版本,它将完整嵌套的指针渲染为可重用的代码:

package main

import (
	"fmt"
	"github.com/gdexlab/go-render/render"
)

type A struct {
	a int32
	B *B
}
type B struct {
	b int32
}

func main() {
	a := &A{
		a: 1,
		B: &B{
			b: 2,
		},
	}
	output := render.AsCode(a)
	fmt.Println(output)

}
// 输出:"&A{a:1, B:&B{b:2}}",与初始版本"&{a:1 B:0xc42000e204}"进行比较

Go Playground 示例:
https://play.golang.org/p/tcfJYb0NnVf

英文:

When you get into larger structs, it becomes a pain to write a bunch of custom String functions. Goconvey currently uses the following project to show diffs and expected/actual output on structs of any size: https://github.com/luci/go-render/blob/master/render/render.go#L51. It includes displaying pointer values.

If you need the output to be re-usable as code (like fmt.Printf("%#v", a) but include pointer values), I have a forked version of the above project which will render full nested pointers as re-usable code:

package main

import (
	"fmt"
	"github.com/gdexlab/go-render/render"
)

type A struct {
	a int32
	B *B
}
type B struct {
	b int32
}

func main() {
	a := &A{
		a: 1,
		B: &B{
			b: 2,
		},
	}
	output := render.AsCode(a)
	fmt.Println(output)

}
// outputs: "&A{a:1, B:&B{b:2}}" compared to initial version of "&{a:1 B:0xc42000e204}"

Go Playground Example:
https://play.golang.org/p/tcfJYb0NnVf

答案3

得分: 8

另一个简单的解决方案是使用编组(marshaling)来打印结构体。这仅适用于在结构体内部将首字母大写的导出(公共)变量。

package main

import (
	"fmt"
	"gopkg.in/yaml.v2"
	"encoding/json"
)

type A struct {
	Aa int32
	B *B
}
type B struct {
	Bb int32
}
func main() {
	a := &A{
		Aa: 1,
		B: &B{
			Bb: 2,
		},
	}
	aJSON, _ := json.Marshal(a)
	fmt.Printf("JSON Print - \n%s\n", string(aJSON))


	aYAML, _ := yaml.Marshal(a)
	fmt.Printf("YAML Print - \n%s\n", string(aYAML))
}

输出:

JSON Print - 
{"Aa":1,"B":{"Bb":2}}
YAML Print - 
aa: 1
b:
  bb: 2

如果要多次打印结构体,则可以实现Stringer接口,如下所示:

package main

import (
	"fmt"
	"gopkg.in/yaml.v2"
)

type A struct {
	Aa int32
	B *B
}

func (a A) String() string {
	bytes, _ := yaml.Marshal(a)
	return string(bytes)
}

type B struct {
	Bb int32
}

func main() {
	a := &A{
		Aa: 1,
		B: &B{
			Bb: 2,
		},
	}

	fmt.Printf("YAML Print - \n%+v\n", a)
}

输出:

YAML Print - 
aa: 1
b:
  bb: 2
英文:

Another simple solution is to print the struct using marshaling. This works only for exported (public) variables by capitalizing the first char inside the struct.

package main

import (
	"fmt"
	"gopkg.in/yaml.v2"
	"encoding/json"
)

type A struct {
	Aa int32
	B *B
}
type B struct {
	Bb int32
}
func main() {
	a := &A{
		Aa: 1,
		B: &B{
			Bb: 2,
		},
	}
	aJSON, _ := json.Marshal(a)
	fmt.Printf("JSON Print - \n%s\n", string(aJSON))


	aYAML, _ := yaml.Marshal(a)
	fmt.Printf("YAML Print - \n%s\n", string(aYAML))
}

Output :-

JSON Print - 
{"Aa":1,"B":{"Bb":2}}
YAML Print - 
aa: 1
b:
  bb: 2

If you are printing the struct multiple times then implement Stringer interface as follows :-

package main

import (
	"fmt"
	"gopkg.in/yaml.v2"
)

type A struct {
	Aa int32
	B *B
}

func (a A) String() string {
	bytes, _ := yaml.Marshal(a)
	return string(bytes)
}

type B struct {
	Bb int32
}

func main() {
	a := &A{
		Aa: 1,
		B: &B{
			Bb: 2,
		},
	}

	fmt.Printf("YAML Print - \n%+v\n", a)
}

Output -

YAML Print - 
aa: 1
b:
  bb: 2

答案4

得分: 3

使用 fmt 和 reflect。

package main

import (
	"fmt"
	"reflect"
)

type A struct {
	a int32
	B *B
}
type B struct {
	b int32
}

func main() {
	a := &A{
		a: 1,
		B: &B{
			b: 2,
		},
	}
	fmt.Printf("%s\n", GetGoString(a)) // 输出: &A{a: 1, B: &B{b: 2}}
}

func GetGoString(v interface{}) string {
	return getGoString(reflect.ValueOf(v))
}

func getGoString(v reflect.Value) string {
	switch v.Kind() {
	case reflect.Invalid:
		return "nil"
	case reflect.Struct:
		t := v.Type()
		out := getTypeString(t) + "{"
		for i := 0; i < v.NumField(); i++ {
			if i > 0 {
				out += ", "
			}
			fieldValue := v.Field(i)
			field := t.Field(i)
			out += fmt.Sprintf("%s: %s", field.Name, getGoString(fieldValue))
		}
		out += "}"
		return out
	case reflect.Interface, reflect.Ptr:
		if v.IsZero() {
			return fmt.Sprintf("(%s)(nil)", getTypeString(v.Type()))
		}
		return "&" + getGoString(v.Elem())
	case reflect.Slice:
		out := getTypeString(v.Type())
		if v.IsZero() {
			out += "(nil)"
		} else {
			out += "{"
			for i := 0; i < v.Len(); i++ {
				if i > 0 {
					out += ", "
				}
				out += getGoString(v.Index(i))
			}
			out += "}"
		}
		return out
	default:
		return fmt.Sprintf("%#v", v)
	}
}

func getTypeString(t reflect.Type) string {
	if t.PkgPath() == "main" {
		return t.Name()
	}
	return t.String()
}

希望对你有帮助!

英文:

Use fmt and reflect.

package main
import (
&quot;fmt&quot;
&quot;reflect&quot;
)
type A struct {
a int32
B *B
}
type B struct {
b int32
}
func main() {
a := &amp;A{
a: 1,
B: &amp;B{
b: 2,
},
}
fmt.Printf(&quot;%s\n&quot;, GetGoString(a)) // output: &amp;A{a: 1, B: &amp;B{b: 2}}
}
func GetGoString(v interface{}) string {
return getGoString(reflect.ValueOf(v))
}
func getGoString(v reflect.Value) string {
switch v.Kind() {
case reflect.Invalid:
return &quot;nil&quot;
case reflect.Struct:
t := v.Type()
out := getTypeString(t) + &quot;{&quot;
for i := 0; i &lt; v.NumField(); i++ {
if i &gt; 0 {
out += &quot;, &quot;
}
fieldValue := v.Field(i)
field := t.Field(i)
out += fmt.Sprintf(&quot;%s: %s&quot;, field.Name, getGoString(fieldValue))
}
out += &quot;}&quot;
return out
case reflect.Interface, reflect.Ptr:
if v.IsZero() {
return fmt.Sprintf(&quot;(%s)(nil)&quot;, getTypeString(v.Type()))
}
return &quot;&amp;&quot; + getGoString(v.Elem())
case reflect.Slice:
out := getTypeString(v.Type())
if v.IsZero() {
out += &quot;(nil)&quot;
} else {
out += &quot;{&quot;
for i := 0; i &lt; v.Len(); i++ {
if i &gt; 0 {
out += &quot;, &quot;
}
out += getGoString(v.Index(i))
}
out += &quot;}&quot;
}
return out
default:
return fmt.Sprintf(&quot;%#v&quot;, v)
}
}
func getTypeString(t reflect.Type) string {
if t.PkgPath() == &quot;main&quot; {
return t.Name()
}
return t.String()
}

答案5

得分: 2

实现Stringer接口来自定义type

  • 不使用外部包
  • 不需要将类型包装在其他类型中

示例:

package main

import "fmt"

type A struct {
	B *B `json:"b"`
}

type B int

func (b *B) String() string {
	if b == nil {
		return "nil"
	}

	return fmt.Sprintf("%d", *b)
}

func main() {
    var a A
    fmt.Printf("a: %+v\n", a)
    a.B = B(3)
    fmt.Printf("a: %+v\n", a)
}

输出:

a: {B:nil}
a: {B:3}
英文:

Implement Stringer interface to custom type

  • no external packages
  • no need to wrap types in other types

example:

package main

import &quot;fmt&quot;

type A struct {
	B *B `json:&quot;b&quot;`
}

type B int

func (b *B) String() string {
	if b == nil {
		return &quot;nil&quot;
	}

	return fmt.Sprintf(&quot;%d&quot;, *b)
}

func main() {
    var a A
    fmt.Printf(&quot;a: %+v\n&quot;, a)
    a.B = B(3)
    fmt.Printf(&quot;a: %+v\n&quot;, a)
}

output:

a: {B:nil}
a: {B:3}

huangapple
  • 本文由 发表于 2017年4月6日 23:48:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/43259971.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定