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

简介:

通常在尝试打印 结构时 ,我们会使用%v来显示结构的所有数据。它将打印结构中每个字段的默认格式。

 
%v默认格式的值
打印结构时,加号标志(%+ v)添加字段名称

但是最近我们在使用嵌套结构打印结构时发现了一个奇怪的行为,该结构具有一个 String()字符串%v 格式根据我们的理解打印出“意外”输出。

我们先看看示例代码段。

 
package main import ( "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)}

我们期望产量

{任何东西A}

但实际结果是

什么

这没有意义,对吧?这似乎 FIELDA 如果被忽略 的字符串()字符串 是为实现 内部 结构类型。

根据我们的理解,struct A类型有两个字段: InnerFieldA,在打印值时,它将循环遍历字段并使用其默认格式进行打印。所以Inner应该调用它的String(),而FieldA将打印它的字符串值。但是,上述输出让我们怀疑我们的理解。

仔细研究一下这些文档之后,它就有了以下规则。

 ●  如果格式(对于Println等隐式%v)对字符串有效(%s%q%v%x%X),则适用以下两个规则:

 ●  如果操作数实现了错误接口,则将调用Error方法将对象转换为字符串,然后根据动词的需要对其进行格式化(如果有)。

如果操作数实现方法String()字符串,则将调用该方法将对象转换为字符串,然后根据动词的需要对其进行格式化(如果有)。

由于 Inner 是一个操作数,它实现了 String()字符串 方法,该方法被视为 Stringer 接口,因此在打印时会调用它。这解释了我们实际看到的输出。下面实际上是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 }}

现在如果我们在A中有两个嵌套结构并且它们都实现了 String()字符串 怎么办?

 
package main import ( "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)}

输出是我们最初的预期

{什么都不是啊}

上面输出的原因是调用String()是不明确的,因此它将回退遍历所有字段并以默认格式获取它们的值。

请注意Go提供的上述行为,以便在使用%v格式在日志中打印struct时不会错过一些重要数据。


原文发布时间为:2018-11-11

本文来自云栖社区合作伙伴“Golang语言社区”,了解相关信息可以关注“Golang语言社区”。

相关文章
|
2月前
|
Go
Golang语言流程控制之for循环结构篇
这篇文章详细介绍了Golang语言中的for循环结构,包括for循环的基本写法、引入、原理、死循环案例,for range键值循环的使用,以及break、continue、goto和return关键字在循环控制中的运用,并提供了练习题来加深理解。
23 0
Golang语言流程控制之for循环结构篇
|
5月前
|
SQL 关系型数据库 MySQL
mysqldiff - Golang 针对 MySQL 数据库表结构的差异 SQL 工具
Golang 针对 MySQL 数据库表结构的差异 SQL 工具。https://github.com/camry/mysqldiff
92 7
|
5月前
|
JSON Go 数据格式
技术经验分享:Golang如何解组嵌套的JSON数据的子集
技术经验分享:Golang如何解组嵌套的JSON数据的子集
|
5月前
|
JSON Go 数据格式
【golang】json数据解析 - 嵌套json解析
【golang】json数据解析 - 嵌套json解析
70 0
|
6月前
|
Java Go C++
Golang每日一练(leetDay0118) 扁平化嵌套列表迭代器、整数拆分
Golang每日一练(leetDay0118) 扁平化嵌套列表迭代器、整数拆分
58 0
Golang每日一练(leetDay0118) 扁平化嵌套列表迭代器、整数拆分
|
6月前
|
Go
深入了解 Golang 条件语句:if、else、else if 和嵌套 if 的实用示例
条件语句用于根据不同的条件执行不同的操作。 Go中的条件可以是真或假。 Go支持数学中常见的比较运算符: 小于 < 小于等于 <= 大于 > 大于等于 >= 等于 == 不等于 != 此外,Go还支持常见的逻辑运算符: 逻辑与 && 逻辑或 || 逻辑非 ! 您可以使用这些运算符或它们的组合来创建不同决策的条件。 示例 尝试一下 x > y x != y (x > y) && (y > z) (x == y) || z Go具有以下条件语句: 使用if来指定在指定条件为真时执行的代码块 使用else来指定在相同条件为假时执行的代码块 使用else if来指定要测试的新条件,如果第
111 2
|
编译器 Go
Golang:Go语言结构
Go 语言结构 在我们开始学习 Go 编程语言的基础构建模块前,让我们先来了解 Go 语言最简单程序的结构。
241 0
|
存储 编译器 Go
100天精通Golang(基础入门篇)——第8天:Go语言程序的流程结构和条件语句
100天精通Golang(基础入门篇)——第8天:Go语言程序的流程结构和条件语句
60 0
|
编译器 Go 索引
巨细靡遗流程控制,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang流程结构详解EP09
流程结构就是指程序逻辑到底怎么执行,进而言之,程序执行逻辑的顺序。众所周知,程序整体都是自上由下执行的,但有的时候,又不仅仅是从上往下执行那么简单,大体上,Go lang程序的流程控制结构一共有三种:顺序结构,选择结构,循环结构。顺序结构:从上向下,逐行执行;选择结构:条件满足,某些代码才会执行,0-1次;循环结构:条件满足,某些代码会被反复的执行多次,0-N次
巨细靡遗流程控制,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang流程结构详解EP09
|
Go Python
Golang学习之路(二):Golang的语言结构和变量
Golang学习之路(二):Golang的语言结构和变量
144 0
Golang学习之路(二):Golang的语言结构和变量