英文:
GoYAML struct slices
问题
我正在尝试学习goyaml,并且在尝试从yaml中生成切片时遇到了一些问题。我可以将我的结构体编组成这个示例yaml,但是我无法将相同的yaml解组回结构体中。
结构体:
type Configuration struct{
Input ioInstance
Processing ProcessingInstance
Output ioInstance
}
type ioInstance struct {
File []FileInstance
Webservice []WebserviceInstance
}
type FileInstance struct {
File string
}
type WebserviceInstance struct {
Port string
Address string
}
type ProcessingInstance struct {
Regex []RegexInstance
}
type RegexInstance struct {
Regex string
Mapping string
}
在测试解组时,我遇到了反射错误,据我了解,我认为我可能需要重新设计,不使用结构体切片,我希望有人能提供一些见解。
错误信息:
panic: reflect: reflect.Value.Set using unaddressable value [recovered]
panic: reflect: reflect.Value.Set using unaddressable value [recovered]
panic: reflect: reflect.Value.Set using unaddressable value
英文:
I am attempting to learn goyaml, and am having some issues with attempting to produce slices from yaml. I can marshal my struct into this example yaml, but I cannot unmarshal the same yaml back into the struct.
input:
file:
- file: stdin
webservice:
- port: "0000"
address: 0.0.0.0
processing:
regex:
- regex: ^(this)*
mapping: (1) thing
output:
file:
- file: stdout
webservice:
- port: "0000"
address: 0.0.0.0
struct:
type Configuration struct{
Input ioInstance
Processing ProcessingInstance
Output ioInstance
}
type ioInstance struct {
File []FileInstance
Webservice []WebserviceInstance
}
type FileInstance struct {
File string
}
type WebserviceInstance struct {
Port string
Address string
}
type ProcessingInstance struct {
Regex []RegexInstance
}
type RegexInstance struct {
Regex string
Mapping string
}
When testing unmarshaling I'm getting reflect errors, as I understand it I think I may need to re-approach the design without struct slices, I was hoping someone could offer some insight into this?
errors:
panic: reflect: reflect.Value.Set using unaddressable value [recovered]
panic: reflect: reflect.Value.Set using unaddressable value [recovered]
panic: reflect: reflect.Value.Set using unaddressable value
答案1
得分: 4
以下是翻译好的内容:
以下代码对我来说完全正常,按照应该的方式输出原始的yaml文本:
package main
import "fmt"
import "gopkg.in/yaml.v2"
func main() {
c := &Configuration{}
yaml.Unmarshal([]byte(yamlText), c)
buf, _ := yaml.Marshal(c)
fmt.Println(string(buf))
}
var yamlText = `
input:
file:
- file: stdin
webservice:
- port: "0000"
address: 0.0.0.0
processing:
regex:
- regex: ^(this)*
mapping: (1) thing
output:
file:
- file: stdout
webservice:
- port: "0000"
address: 0.0.0.0
`
type Configuration struct {
Input ioInstance
Processing ProcessingInstance
Output ioInstance
}
type ioInstance struct {
File []FileInstance
Webservice []WebserviceInstance
}
type FileInstance struct {
File string
}
type WebserviceInstance struct {
Port string
Address string
}
type ProcessingInstance struct {
Regex []RegexInstance
}
type RegexInstance struct {
Regex string
Mapping string
}
输出:
input:
file:
- file: stdin
webservice:
- port: "0000"
address: 0.0.0.0
processing:
regex:
- regex: ^(this)*
mapping: (1) thing
output:
file:
- file: stdout
webservice:
- port: "0000"
address: 0.0.0.0
(当然,在实际代码中,你不应该忽略错误,就像我在这里做的一样。)
编辑:
Unmarshal
需要一个指向结构体的指针来设置其字段。如果你使用一个普通的结构体值调用它,它只会接收到原始结构体的一个副本(因为在 Go 中,所有东西都是按值传递的),因此无法修改原始结构体的字段。
因此,你基本上有两个选择:
你可以使用 c := &Configuration{}
来定义和初始化 c
,即将其定义为指向 Configuration
类型的指针,同时将其指向一个新的、零值的 Configuration
值。然后你可以调用 yaml.Unmarshal([]byte(yamlText), c)
。
或者你可以使用 var c Configuration
来定义 c
,这意味着 c
不是一个指针,而是 Configuration
类型的新的零值。在这种情况下,当你调用 Unmarshal
时,你需要显式地传递一个指向该值的指针:yaml.Unmarshal([]byte(yamlText), &c)
。
注意,你传递给 Unmarshal 的指针必须指向一个已存在的 Configuration
值。var c *Configuration
会将 c
定义为一个指针,但是立即将其传递给 Unmarshal
会导致恐慌,因为它的值是 nil
;它没有指向一个已存在的 Configuration
值。
另外,在我上面的代码中最初有一个小错误,现在已经修复了(尽管代码仍然可以工作)。我写了 c := &Configuration{}
和 yaml.Unmarshal([]byte(yamlText), &c)
,所以我实际上传递给 Unmarshal
的是 指向指针的指针,而 Unmarshal
能够处理这个问题。
英文:
The following code works just fine for me, outputting the original yaml text as it should:
package main
import "fmt"
import "gopkg.in/yaml.v2"
func main() {
c := &Configuration{}
yaml.Unmarshal([]byte(yamlText), c)
buf, _ := yaml.Marshal(c)
fmt.Println(string(buf))
}
var yamlText = `
input:
file:
- file: stdin
webservice:
- port: "0000"
address: 0.0.0.0
processing:
regex:
- regex: ^(this)*
mapping: (1) thing
output:
file:
- file: stdout
webservice:
- port: "0000"
address: 0.0.0.0
`
type Configuration struct {
Input ioInstance
Processing ProcessingInstance
Output ioInstance
}
type ioInstance struct {
File []FileInstance
Webservice []WebserviceInstance
}
type FileInstance struct {
File string
}
type WebserviceInstance struct {
Port string
Address string
}
type ProcessingInstance struct {
Regex []RegexInstance
}
type RegexInstance struct {
Regex string
Mapping string
}
Output:
input:
file:
- file: stdin
webservice:
- port: "0000"
address: 0.0.0.0
processing:
regex:
- regex: ^(this)*
mapping: (1) thing
output:
file:
- file: stdout
webservice:
- port: "0000"
address: 0.0.0.0
(Of course you should not ignore errors in your actual code, like I'm doing here.)
EDIT:
Unmarshal
needs a pointer to a struct in order to set its fields. If you call it with a plain struct value, it receives only a copy of the original struct (because in Go everything is passed as a copy), and therefore couldn't possibly alter the fields of the original struct.
Therefore, you have basically two options:
You can define and initialize c
with c := &Configuration{}
, i.e. defining it as a pointer to type Configuration
while simultaneously pointing it to a new, zeroed Configuration
value. Then you can call yaml.Unmarshal([]byte(yamlText), c)
.
Alternatively you can define c
with var c Configuration
, which means c
is not a pointer, but a new zero value of type Configuration
. In this case you need to explicitly pass a pointer to that value when you call Unmarshal
: yaml.Unmarshal([]byte(yamlText), &c)
.
Note that the pointer you pass to Unmarshal must point to an existing Configuration
value. var c *Configuration
would define c
as a pointer, but passing it immediately to Unmarshal
would lead to an panic, as it's value is nil
; it doesn't point to an existing Configuration
value.
Also, in my code above there was originally a little typo, which is now fixed (though the code still worked). I wrote both c := &Configuration{}
and yaml.Unmarshal([]byte(yamlText), &c)
, so I actually passed Unmarshal
a pointer to a pointer to a struct, which Unmarshal
was able to handle without issues.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论