英文:
string from stream in go for multiple object types
问题
我习惯使用Java,并在Google Go中进行初步设置。我有一个包含子对象等的对象树。这个树会递归地转储到io.Writer中。输出可能非常庞大,所以我不想为每个对象创建一个字符串,并在内存中连接结果。
为了调试目的,我想要在这个树的部分中使用fmt.Printf。因此,我想要在每个对象上创建一个通用的String()函数,该函数调用ToStream函数,并将结果作为字符串返回。在Java中,这很容易:在基类上创建该方法。在GO中,我该如何做到这一点,而不需要为每种类型的对象创建自定义的String方法。
请参考以下代码,特别是标记为ERROR的行:
package main
import (
"io"
"fmt"
"bytes"
)
//Base是用于批量输出的接口
type Base interface {
ToStream(io.Writer)
}
//Impl1具有Base接口
type Impl1 struct{
stuff int
}
func (Impl1) ToStream(w io.Writer) {
fmt.Fprintf(w, "A lot of stuff")
}
//Impl2具有Base接口
type Impl2 struct{
otherstuff int
}
func (Impl2) ToStream(w io.Writer) {
fmt.Fprintf(w, "A lot of other stuff")
}
//我想要将任何基类转换为用于调试输出的字符串
//这应该通过ToStream方法实现
func (v Base) String() string {//错误在这里:无效的接收器类型Base(Base是一个接口类型)
//func (v Impl1) String() string {//这样可以工作,但需要为每个struct Impl1、Impl2等重新实现
var buffer bytes.Buffer
v.ToStream(&buffer)
return string(buffer.Bytes())
}
func main(){
aBase:= new(Impl1)
fmt.Printf("%s\n",aBase)
}
英文:
I'm used to Java, and setting first steps in google go. I have a tree of objects with child objects etc... This tree is recursively dumped to an io.Writer. Output might be huge, so I don't want to create a string for each object, and concatenate the result in memory..
For debugging purposes, i want to fmt.Printf parts of this tree. Thus, I want to create a generic String() function on each object in which calls the ToStream function, returning the result as a string. In Java, this is easy: create the method on the base class. How do I do this in GO, without creating a custom String method for each kind of object.
See the code for what I want, specifically the line marked 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)
}
答案1
得分: 3
似乎你在这里被Java的思维所限制了
虽然Java只有方法,但Go确实有函数。当然,你不能在接口上定义方法,但你可以创建一个接受Base
类型参数并执行操作的普通函数:
func Base2String(b Base) string {
var buffer bytes.Buffer
b.ToStream(&buffer)
return string(buffer.Bytes())
}
现在,如果你将Base
重命名为符合Go语言风格的名称(记住,Go语言中没有类型层次结构),你就会得到一些漂亮的代码。
英文:
Seems like Java thinking blocked you here
While Java has methods only Go does have functions. And of course you cannot have methods on an interface but you can make a plain function taking a Base
and doing stuff:
func Base2String(b Base) string {
var buffer bytes.Buffer
b.ToStream(&buffer)
return string(buffer.Bytes())
}
Now if you rename Base to something Go-ish (remember there is no type hierarchy in Go) you have some nice code.
答案2
得分: 1
你可以使用一个包装器来添加必要的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 := StreamerToStringer{new(Impl1)}
aBase2 := StreamerToStringer{new(Impl2)}
fmt.Printf("%s\n", aBase1)
fmt.Printf("%s\n", aBase2)
// 这些包装后的值仍然支持ToStream()方法。
var buffer bytes.Buffer
aBase1.ToStream(&buffer)
fmt.Println(buffer.Bytes())
}
请注意,这只是一个示例代码,Impl1
和Impl2
是示意的实现类型。你需要根据实际情况进行适当的修改。
英文:
You can wrap around a Base to add the necessary String()
function. Here is one approach:
type StreamerToStringer struct {
Base
}
func (s StreamerToStringer) String() string {
var buffer bytes.Buffer
s.Base.ToStream(&buffer)
return string(buffer.Bytes())
}
With this, you can augment any Base
instance so it has a String()
method.
func main() {
aBase1 := StreamerToStringer{new(Impl1)}
aBase2 := StreamerToStringer{new(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())
}
答案3
得分: 0
首先,你可以尝试使用以下代码来打印信息:
fmt.Printf("%+v\n", yourProject)
查看打印出的信息是否足够开始使用。fmt
包中提到:
当打印结构体时,加号标志(%+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|
}
英文:
It is easier to first call:
fmt.Printf("%+v\n", yourProject)
See if the information printed are enough for a start: the fmt
package mentions
> when printing structs, the plus flag (%+v) adds field names
If that is not enough, then you would have to use reflection, as I mentioned in "Golang - How to print struct variables in console?".
Or you can have a look at the project davecgh/go-spew
(mentioned in "Go-spew: A Journey into Dumping Go Data Structures")
> Go-spew
implements a deep pretty printer for Go data structures to aid in debugging
spew.Dump(myVar1, myVar2, ...)
spew.Fdump(someWriter, myVar1, myVar2, ...)
str := spew.Sdump(myVar1, myVar2, ...)
That would print something like:
(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|
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论