英文:
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 (
"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)) // output: &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()
}
答案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 "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)
}
output:
a: {B:nil}
a: {B:3}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论