golang之带指针的结构体格式化打印

 

https://www.jianshu.com/p/1b04d75769a7

Golang里的格式化字符额外提供了%v%+v%#v,可以用作打印一些基础类型的值,同时也支持打印接口和结构体。

func main() {
    num := 1
    str := "ted"
    sleep := false
    fmt.Printf("num: %v, str: %v, sleep: %v\n", num, str, sleep)

    stu := student{
        id:   0,
        name: "ted",
    }
    var numInterface  interface{}
    numInterface=num
    fmt.Printf("stu: %v, numInterface: %v\n", stu, numInterface)
    fmt.Printf("stu: %+v, numInterface: %+v\n", stu, numInterface)
    fmt.Printf("stu: %#v, numInterface: %#v\n", stu, numInterface)
}

上述代码的执行结果如下:

num: 1, str: ted, sleep: false
stu: {0 ted}, numInterface: 1
stu: {id:0 name:ted}, numInterface: 1
stu: main.student{id:0, name:"ted"}, numInterface: 1
  • %v在打印接口类型时,会打印出其实际的值。而在打印结构体对象时,打印的是结构体成员对象的值。
  • %+v打印结构体对象中的字段类型+字段值。
  • %#v先打印结构体名,再输出结构体对象的字段类型+字段的值。

同理当结构体中存在指针成员时,打印的指针成员的值是指针本身的值,而不是指针指向的值,参考如下代码:

package main
import "fmt"
 
type student struct {
    id   int32
    name *string
}
 
func main() {
    name := "gxt"
    stu := student{id: 1, name: &name}
    
    fmt.Printf("stu: %v\n", stu)
    fmt.Printf("stu: %+v\n", stu)
    fmt.Printf("stu: %#v\n", stu)
}

输出结果:

stu: {1 0xc000010240}
stu: {id:1 name:0xc000010240}
stu: main.student{id:1, name:(*string)(0xc000010240)}

实际上Golang的fmt包中已经提供了Stringers接口用于自定义某种类型的字符串打印信息。

// Stringer is implemented by any value that has a String method,
// which defines the ``native'' format for that value.
// The String method is used to print values passed as an operand
// to any format that accepts a string or to an unformatted printer
// such as Print.
type Stringer interface {
    String() string
}

因此只需要给上述代码中的student结构体实现该接口即可。参考代码如下:


package main
import "fmt"
 
type student struct {
    id   int32
    name *string
}

func (s student) String() string {
    return fmt.Sprintf("{id: %v, name: %v}", s.id, *s.name)
}
 
func main() {
    name := "ted"
    stu := student{id: 1, name: &name}
    
    fmt.Printf("stu: %v\n", stu)
    fmt.Printf("stu: %+v\n", stu)
    fmt.Printf("stu: %#v\n", stu)
}

结果如下:

stu: {id: 1, name: ted}
stu: {id: 1, name: ted}
stu: main.student{id:1, name:(*string)(0xc000010240)}

可以看到即使重写了String()方法后,对%#v仍不起作用,在平时编程中要注意这一点。

进一步考虑如果结构体中嵌套了其他结构体对象指针,这种情况需要怎么处理呢?参考如下代码:

package main

import (
    "encoding/json"
    "fmt"
)
type studentP struct {
    id    int32
    name  *string
    score *score
}
type score struct {
    math    *int
    english int
}

func (s *studentP) String() string {
    return fmt.Sprintf("{id: %v, name: %v, score: %v}", s.id, *s.name, s.score)
}

func (s *score) String() string {
    return fmt.Sprintf("{math:%v, english:%v}", *s.math, s.english)
}

func main() {
    name := "gxt"
    math := 99
    stu := &studentP{
        id:   0,
        name: &name,
        score: &score{
            math:    &math,
            english: 100,
        },
    }

    fmt.Printf("std: %v\n",stu)
}

结果如下:

std: {id: 0, name: gxt, score: {math:99, english:100}}

上述代码中,即使是嵌套了指针类型的结构体对象,只要子结构体对象也实现了String()方法,也可以正常通过%v%+v打印出结构体的各个成员内容。整体机制比较类似于Java语言中的toString()方法。

注意:在实现String()方法时,需要注意receiver是对象还是指针,关系到打印嵌套式结构体对象时的传参。



作者:LandscapeTed
链接:https://www.jianshu.com/p/1b04d75769a7
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
posted @   浮尘微光  阅读(3909)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
历史上的今天:
2021-04-12 phpstorm改代码区的字体与大小 &&改左侧目录栏文字大小
2021-04-12 “xxx.app”已损坏,无法打开,你应该将它移到废纸篓 最详细最全的解决办法 for Mac
2019-04-12 PHP抽象类与接口的区别
2019-04-12 关于进程和线程
2017-04-12 常用 Git 命令清单
2017-04-12 广告中的AdNetwork、AdExchange、DSP、SSP、RTB和DMP是什么?
点击右上角即可分享
微信分享提示