首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >动态解封yaml在戈朗

动态解封yaml在戈朗
EN

Stack Overflow用户
提问于 2017-12-15 06:36:53
回答 1查看 2K关注 0票数 2

编辑:添加问题上下文

我正在为ArangoDB数据库制作一个迁移工具。不知道那是什么?退房https://www.arangodb.com。现在,和大多数迁移工具一样,我的工具需要创建集合,这在逻辑上相当于SQL表。它需要创建或删除索引、集合、图形和其他DB实体,并执行任意AQL (用于ArangoDB的SQL代数)。

为了支持这一点,用户创建了一系列迁移文件,每个文件都说明了如何处理该步骤。所以第一步可能会说“创建集合用户”,步骤67可能会说“删除集合用户--因为我们重新命名了它”。我想使用YAML,因为ArangoDB团队明确地问了我为什么不使用。Golang似乎是一个比我现有的Java实现更好的选择,因为不需要Java的二进制发行版。

尽管如此,我有几种不同类型的结构存储在不同的yaml文件中。我可以通过读取yaml的第一行来判断哪个结构在哪个文件中。我想尽可能的干净利落地读文件。

我试图让一个工厂方法从这个代码中的文件中创建正确的结构。我们可以假设pickT的所有实例都将返回迁移接口的有效实现。

代码语言:javascript
运行
复制
func pickT(contents []byte) (Migration, error) {
    s := string(contents)
    switch {
    case collection.MatchString(s):
        return new(Collection), nil
    default:
        return nil, errors.New("Can't determine YAML type")
    }
}

func toStruct(childPath string) Migration {
    contents := open(childPath)

    t, err := pickT(contents)
    if err != nil {
        log.Fatal(err)
    }
    //c := Collection{}
    err = yaml.UnmarshalStrict(contents, &t)
    if err != nil {
        log.Fatal(err)
    }
    return t
}

此代码不起作用。Yaml将显示下面的错误。

代码语言:javascript
运行
复制
--- FAIL: TestLoadFromPath (0.00s)
panic: reflect.Set: value of type map[interface {}]interface {} is not assignable to type main.Migration [recovered]
    panic: reflect.Set: value of type map[interface {}]interface {} is not assignable to type main.Migration [recovered]
    panic: reflect.Set: value of type map[interface {}]interface {} is not assignable to type main.Migration

goroutine 5 [running]:
testing.tRunner.func1(0xc4201060f0)
    /usr/local/go/src/testing/testing.go:711 +0x2d2
panic(0x68ade0, 0xc420010cf0)
    /usr/local/go/src/runtime/panic.go:491 +0x283
gopkg.in/yaml%2ev2.handleErr(0xc420057b18)
    /home/jdavenpo/go/src/gopkg.in/yaml.v2/yaml.go:164 +0x9f
panic(0x68ade0, 0xc420010cf0)
    /usr/local/go/src/runtime/panic.go:491 +0x283
reflect.Value.assignTo(0x69e740, 0xc42007d230, 0x15, 0x6f30e4, 0xb, 0x6a45a0, 0xc420010cd0, 0x69e740, 0xc42007d230, 0x15)
    /usr/local/go/src/reflect/value.go:2192 +0x3a6
reflect.Value.Set(0x6a45a0, 0xc420010cd0, 0x194, 0x69e740, 0xc42007d230, 0x15)
    /usr/local/go/src/reflect/value.go:1357 +0xa4
gopkg.in/yaml%2ev2.(*decoder).mapping(0xc420060900, 0xc4200644e0, 0x6a45a0, 0xc420010cd0, 0x194, 0x6a45a0)
    /home/jdavenpo/go/src/gopkg.in/yaml.v2/decode.go:522 +0x8e2
gopkg.in/yaml%2ev2.(*decoder).unmarshal(0xc420060900, 0xc4200644e0, 0x6a45a0, 0xc420010cd0, 0x194, 0xc4200644e0)
    /home/jdavenpo/go/src/gopkg.in/yaml.v2/decode.go:292 +0x136
gopkg.in/yaml%2ev2.(*decoder).document(0xc420060900, 0xc420064480, 0x6a45a0, 0xc420010cd0, 0x194, 0xc4200608c0)
    /home/jdavenpo/go/src/gopkg.in/yaml.v2/decode.go:304 +0x80
gopkg.in/yaml%2ev2.(*decoder).unmarshal(0xc420060900, 0xc420064480, 0x6a45a0, 0xc420010cd0, 0x194, 0x194)
    /home/jdavenpo/go/src/gopkg.in/yaml.v2/decode.go:280 +0x1d2
gopkg.in/yaml%2ev2.unmarshal(0xc42010c000, 0x3b, 0x23b, 0x67c4a0, 0xc420010cd0, 0x1, 0x0, 0x0)
    /home/jdavenpo/go/src/gopkg.in/yaml.v2/yaml.go:101 +0x289
gopkg.in/yaml%2ev2.UnmarshalStrict(0xc42010c000, 0x3b, 0x23b, 0x67c4a0, 0xc420010cd0, 0x0, 0x0)
    /home/jdavenpo/go/src/gopkg.in/yaml.v2/yaml.go:87 +0x58
github.com/deusdat/arangomigo.toStruct(0xc420014360, 0x26, 0x0, 0x0)
    /home/jdavenpo/go/src/github.com/deusdat/arangomigo/migrations.go:102 +0x295
github.com/deusdat/arangomigo.loadFrom(0x6f8059, 0x1a, 0x0, 0x0, 0x0)
    /home/jdavenpo/go/src/github.com/deusdat/arangomigo/migrations.go:67 +0x4d6
github.com/deusdat/arangomigo.TestLoadFromPath(0xc4201060f0)
    /home/jdavenpo/go/src/github.com/deusdat/arangomigo/migrations_test.go:11 +0x48
testing.tRunner(0xc4201060f0, 0x705950)
    /usr/local/go/src/testing/testing.go:746 +0xd0
created by testing.(*T).Run
    /usr/local/go/src/testing/testing.go:789 +0x2de

据我所知,Go类型擦除了接口,至少在功能上是这样。有没有任何方法可以动态地选择类型,然后让Yaml将其转换出来?我知道,我可以通过在下面这样的不同函数中反复重复相同的逻辑来手动完成这一任务,但是这个seems...terrible。

代码语言:javascript
运行
复制
func fromCollectionYaml(content string) Migration {
    c := Collection{}
    err := yaml.Unmarshal(content, &c)
    if err != nil {
        log.Fatal(err)
    }
    return c
}

编辑:添加集合结构和Yaml

代码语言:javascript
运行
复制
type: collection
Action: create
Name: Users
Journalsize: 10

type Collection struct {
    Name           string
    Action         Action
    ShardKeys      []string
    JournalSize    int
    NumberOfShards int
    WaitForSync    bool
    AllowUserKeys  bool
    Volatile       bool
    Compactable    bool
}

func (this Collection) migrate(action Action, db *arangolite.Database) error {
    return nil
}

在不久的将来,我需要为索引添加结构。图形和其他与ArangoDB相关的特性。每个Yaml文件都需要进入生成和迁移的结构,这只是一个接口的实例,该接口与当前显示的一个函数以及struct一起显示。

EN

回答 1

Stack Overflow用户

发布于 2020-07-30 10:57:17

我在reddit上找到了这个问题的答案,为了帮助未来的读者,我在下面提供内容,链接到我找到它的帖子。

我认为,解决方案是简单地将t,而不是&t传递给Unmarshal。 基本原理:您需要传递一个指向结构的指针,该指针可以将预期的数据作为接口{}中的动态值传递给Un封送。从pickT返回new(Collection),这是一个指针。但是,首先将其存储在另一种接口类型(迁移)中,然后获取该接口的指针。意思是,yaml将( a)看到它得到一个指针,b)尝试将值存储在切入点中。但是切入点是接口类型(然后这个接口值将包含实际的结构,但yaml不执行这个额外的重定向)。 如果您传递t(它具有接口类型),它将首先被转换为接口{},然后传递-因此参数将按照预期直接包含一个*Collection。 这里的区别是,如果将一种接口类型转换/分配给另一种接口类型,它将不会重新包装,但是一个值中的动态值将被传递给另一个接口类型。但是,如果存储非接口类型(如指向接口的指针),它将重新包装。 恐怕这不容易解释。您也可以在这里看到效果:Pwp (注意,Printf还接受一个接口{})

in/

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47827043

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档