来自流中的字符串,用于多种对象类型
Posted
技术标签:
【中文标题】来自流中的字符串,用于多种对象类型【英文标题】:string from stream in go for multiple object types 【发布时间】:2014-12-17 16:54:22 【问题描述】:我习惯了 Java,并在 google go 中设置了第一步。我有一棵带有子对象等的对象树……这棵树递归地转储到 io.Writer。输出可能很大,所以我不想为每个对象创建一个字符串,并将结果连接到内存中..
出于调试目的,我想 fmt.Printf 这棵树的一部分。因此,我想在调用 ToStream 函数的每个对象上创建一个通用 String() 函数,并将结果作为字符串返回。在 Java 中,这很简单:在基类上创建方法。我如何在 GO 中做到这一点,而不为每种对象创建自定义 String 方法。
查看我想要的代码,特别是标记为 ERROR 的行
package main
import (
"io"
"fmt"
"bytes"
)
//Base is an interface for bulk output
type Base interface
ToStream(io.Writer)
//Impl1 has interface Base
type Impl1 struct
stuff int
func (Impl1) ToStream(w io.Writer)
fmt.Fprintf(w, "A lot of stuff")
//Impl2 has interface Base
type Impl2 struct
otherstuff int
func (Impl2) ToStream(w io.Writer)
fmt.Fprintf(w, "A lot of other stuff")
//I want to convert any base to a sting for debug output
//This should happen by the ToStream method
func (v Base) String() string //ERROR here: Invalid receiver type Base (Base is an interface type)
//func (v Impl1) String() string //This works, but requires re-implementation for every struct Impl1,Impl2,...
var buffer bytes.Buffer
v.ToStream(&buffer)
return string(buffer.Bytes())
func main()
aBase:= new(Impl1)
fmt.Printf("%s\n",aBase)
【问题讨论】:
我们可以向“Base”类添加实现的断言似乎是错误的:Base
是一个接口。接口没有方法,至少在 JDK 8 之前没有,最初的提问者几乎肯定不会在谈论默认的接口方法。提问者可能试图做的是使用继承。更喜欢委托而不是继承方法。
【参考方案1】:
似乎 Java 思维在这里阻止了你 :-)
虽然 Java 有方法,但只有 Go 有 有函数。当然,你不能在接口上使用方法,但你可以制作一个普通函数,使用 Base
并做一些事情:
func Base2String(b Base) string
var buffer bytes.Buffer
b.ToStream(&buffer)
return string(buffer.Bytes())
现在,如果您将 Base 重命名为 Go-ish(记住 Go 中没有类型层次结构),您将获得一些不错的代码。
【讨论】:
【参考方案2】:您可以环绕 Base 以添加必要的 String()
函数。这是一种方法:
type StreamerToStringer struct
Base
func (s StreamerToStringer) String() string
var buffer bytes.Buffer
s.Base.ToStream(&buffer)
return string(buffer.Bytes())
有了这个,您可以扩充任何Base
实例,使其具有String()
方法。
func main()
aBase1 := StreamerToStringernew(Impl1)
aBase2 := StreamerToStringernew(Impl2)
fmt.Printf("%s\n", aBase1)
fmt.Printf("%s\n", aBase2)
// These wrapped values still support ToStream().
var buffer bytes.Buffer
aBase1.ToStream(&buffer)
fmt.Println(buffer.Bytes())
【讨论】:
this 和 Volkers 解决方案都是很好的路径,但是这个允许我使用 fmt.Printf 而不需要包装函数调用。因此,这个解决方案对我来说似乎更可取。谢谢,伙计们!【参考方案3】:先调用比较容易:
fmt.Printf("%+v\n", yourProject)
看看打印的信息是否足以开始:fmt
package 提及
打印结构时,加号标志(%+v)添加字段名称
如果这还不够,那么您将不得不使用反射,正如我在“Golang - How to print struct variables in console?”中提到的那样。
或者你可以看看项目davecgh/go-spew
(在“Go-spew: A Journey into Dumping Go Data Structures”中提到)
Go-spew
为 Go 数据结构实现了一个深度漂亮的打印机以帮助调试
spew.Dump(myVar1, myVar2, ...)
spew.Fdump(someWriter, myVar1, myVar2, ...)
str := spew.Sdump(myVar1, myVar2, ...)
这会打印出类似的东西:
(main.Foo)
unexportedField: (*main.Bar)(0xf84002e210)(
flag: (main.Flag) flagTwo,
data: (uintptr) <nil>
),
ExportedField: (map[interface ]interface )
(string) "one": (bool) true
([]uint8)
00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
00000020 31 32 |12|
【讨论】:
这不是我真正想要的。相应的 ToStream 函数已经成功地以正确的格式转储对象。我的问题是:如何在 ToStream 和 fmt.String 之间编写桥接方法。我的意思是:所有结构的 1 个通用,而不是实现该接口的 20 多个结构的 20 多个。现在,%+v 在其他地方肯定会派上用场,所以我无论如何都学到了一些东西! @user844382 你仍然可以从 go-spec 项目中获得灵感:你需要使用反射。以上是关于来自流中的字符串,用于多种对象类型的主要内容,如果未能解决你的问题,请参考以下文章
提高序列化保存到多种存档类型,并防止在使用指针加载时构造新对象