gpt4 book ai didi

go - 如何避免反射包评估数据类型?

转载 作者:行者123 更新时间:2023-12-01 22:41:18 25 4
gpt4 key购买 nike

对于以下代码:

type Tree struct {
rootLabel interface{}
branches []Tree
}


func printTree(t Tree, nSpaces int) {
labelValue := strings.Repeat(" ", nSpaces) + strconv.Itoa(label(t))
fmt.Println(labelValue)
for _, branch := range branches(t) {
printTree(branch, nSpaces+1)
}
}

func label(t Tree) interface{} {
return t.rootLabel
}
Tree抽象应该允许将任何类型的数据存储在结构字段 rootLabel 中.
但在此语法中假设 label()返回 int , labelValue := strings.Repeat(" ", nSpaces) + strconv.Itoa(label(t)) label(t)返回 interface{}类型断言和类型切换需要猜测工作,所以反射包是替代方案。
但是 recommendation是不要使用 reflect包裹。 reflect.TypeOf(t).String()可以给 main.intmain.string
对于字符串标签 createTree 代码如下所示:
func createTree(label string, branches []Tree) Tree {

    for _, branch := range branches {
        assert(isTree(branch))
    }
    return Tree{
        rootLabel: label,
        branches: branches,
    }
}
$ go version
go version go1.14.3 linux/amd64
如何判断 label(t) 的返回值的具体类型?

最佳答案

好吧,正如 Zyl 在评论中正确写的那样,有一种更简单的方法可以实现这一目标。
备选方案 1:您从其他地方获取树木
基本上,你只能移动“重”的提升,即到fmt.Printf .

package main

import (
"fmt"
"strings"
)

var foo = Tree{
rootLabel: "rootLabel",
branches: []Tree{
Tree{
rootLabel: 42,
branches: []Tree{
Tree{
rootLabel: "subbranch1",
},
},
},
Tree{
rootLabel: "branch2",
branches: []Tree{
Tree{
rootLabel: []byte("frettled"),
},
},
},
},
}

type Tree struct {
rootLabel interface{}
branches []Tree
}

func (t Tree) label() interface{} {
return t.rootLabel
}

func (t *Tree) print(spaces int) {
fmt.Printf("%s%v\n", strings.Repeat(" ", spaces*2), t.label())
for _, b := range t.branches {
b.print(spaces + 1)
}
}

func main() {
foo.print(0)
}
Run on playground
基本上,这可以解决问题。
备选方案 2:您构建树
但是,上述解决方案只会将问题从您的代码中移开。在幕后,使用了反射。
让我们想一想。我们要 rootLabel能够成为任何类型。但我们肯定知道一件事:我们想打印它。空 interface{}太经常被视为“可以是任何东西”的占位符。恕我直言,它应该被视为“我们对此一无所知”,为法国人感到抱歉。但是我们要打印 rootLabel由于接口(interface)描述了行为,我们需要找到合适的接口(interface)。这里是 fmt.Stringer发挥作用。所以基本上,我们需要做的就是更改代码:
package main

import (
"fmt"
"strconv"
"strings"
)

// StringLabel is a label that implements fmt.Stringer
type StringLabel string

// String implements fmt.Stringer for StringLabel
func (l StringLabel) String() string {
return string(l)
}

// ByteSliceLabel is a label that implements fmt.Stringer
type ByteSliceLabel []byte

// String implements fmt.Stringer for ByteSliceLabel
func (l ByteSliceLabel) String() string {
return string(l)
}

// IntLabel is a label that implements fmt.Stringer
type IntLabel int

// String implements fmt.Stringer for IntLabel
func (l IntLabel) String() string {
return strconv.Itoa(int(l))
}

// Bar is an arbitrary example struct.
// However, as long as it implements fmt.Stringer, you can use it as a label.
type Bar struct {
Id int
Baz string
}

// String implements fmt.Stringer for Bar
func (b *Bar) String() string {
return fmt.Sprintf("%03d-%s", b.Id, b.Baz)
}

var foo = Tree{
rootLabel: StringLabel("rootLabel"),
branches: []Tree{
Tree{
rootLabel: IntLabel(42),
branches: []Tree{
Tree{
rootLabel: ByteSliceLabel([]byte("frettled")),
},
},
},
Tree{
rootLabel: StringLabel("branch2"),
branches: []Tree{
Tree{
rootLabel: StringLabel("subbranch2"),
},
Tree{
rootLabel: &Bar{Id: 1, Baz: "lorem"},
},
},
},
},
}

type Tree struct {
rootLabel fmt.Stringer
branches []Tree
}

func (t Tree) label() interface{} {
return t.rootLabel
}

func (t *Tree) print(spaces int) {
fmt.Printf("%s%v\n", strings.Repeat(" ", spaces*2), t.label())
for _, b := range t.branches {
b.print(spaces + 1)
}
}
func main() {
foo.print(0)
}
Run on playground

关于go - 如何避免反射包评估数据类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63540802/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com