如何在Golang中使用字段的String()方法打印结构体
如何在Golang中使用字段的String()方法打印结构体
package main
import (
"bytes"
"fmt"
"reflect"
)
type Email string
type Person struct {
email Email
name string
}
func (e Email) String() string {
return "super secret!"
}
func main() {
foo := Person{
email: "aaa@bbb.com",
name: "Bar",
}
fmt.Println(foo)
}
期望输出:{super secret! Bar},但实际得到:{aaa@bbb.com Bar}
我也尝试过使用反射,但似乎在使用 Field(i) 时丢失了 Email 的类型信息,它只给出了 Email 的基础类型,即 string 或 reflect.String,因此调用的 String() 方法并不是 func (e Email) String() string。
func StructString(s any) string {
v := reflect.ValueOf(s)
t := v.Type()
if t.Kind() != reflect.Struct {
panic("todo")
}
b := &bytes.Buffer{}
b.WriteString("{")
for i := 0; i < v.NumField(); i++ {
if i > 0 {
b.WriteString(" ")
}
// 这里的字段
valField := v.Field(i)
switch valField.Kind() {
case reflect.String:
b.WriteString(valField.String())
default:
// 此处无关...
}
}
b.WriteString("}")
return b.String()
}
更多关于如何在Golang中使用字段的String()方法打印结构体的实战教程也可以访问 https://www.itying.com/category-94-b0.html
2 回复
要实现通过反射调用自定义的 String() 方法,需要检查字段是否实现了 fmt.Stringer 接口,而不是直接判断其类型。以下是修改后的 StructString 函数:
func StructString(s any) string {
v := reflect.ValueOf(s)
t := v.Type()
if t.Kind() != reflect.Struct {
panic("todo")
}
b := &bytes.Buffer{}
b.WriteString("{")
for i := 0; i < v.NumField(); i++ {
if i > 0 {
b.WriteString(" ")
}
field := v.Field(i)
// 检查字段是否实现了fmt.Stringer接口
if stringer, ok := field.Interface().(fmt.Stringer); ok {
b.WriteString(stringer.String())
} else {
// 对于未实现Stringer的字段,使用默认格式化
fmt.Fprintf(b, "%v", field.Interface())
}
}
b.WriteString("}")
return b.String()
}
使用示例:
func main() {
foo := Person{
email: "aaa@bbb.com",
name: "Bar",
}
fmt.Println(StructString(foo)) // 输出: {super secret! Bar}
}
对于更通用的解决方案,可以直接使用 fmt.Fprintf 的 %v 动词,它会自动调用值的 String() 方法:
func StructString(s any) string {
v := reflect.ValueOf(s)
t := v.Type()
if t.Kind() != reflect.Struct {
panic("todo")
}
b := &bytes.Buffer{}
b.WriteString("{")
for i := 0; i < v.NumField(); i++ {
if i > 0 {
b.WriteString(" ")
}
fmt.Fprintf(b, "%v", v.Field(i).Interface())
}
b.WriteString("}")
return b.String()
}
如果需要在 fmt.Println(foo) 中直接输出期望的结果,可以为 Person 结构体实现 String() 方法:
func (p Person) String() string {
return fmt.Sprintf("{%v %s}", p.email, p.name)
}
func main() {
foo := Person{
email: "aaa@bbb.com",
name: "Bar",
}
fmt.Println(foo) // 输出: {super secret! Bar}
}


