英文:
keep precision when unmarshling yaml
问题
我得到了这段代码:
package main
import (
"fmt"
"gopkg.in/yaml.v2"
)
func main() {
kkk := "common:\n vartest1: 1.2000\n vartest2: 1.22233"
tmp := map[string]interface{}{}
yaml.Unmarshal([]byte(kkk), tmp)
fmt.Println(tmp)
}
我期望的是浮点数的精度与字符串保持一致。但是我得到了以下输出:
map[common:map[vartest1:1.2 vartest2:1.22233]]
我尝试了以下代码:
package main
import (
"fmt"
"gopkg.in/yaml.v2"
)
type Myfloat64 float64
func (e *Myfloat64) UnmarshalYAML(unmarshal func(interface{}) error) error {
var test Myfloat64
err := unmarshal(&test)
if err != nil {
return err
}
fmt.Println(test)
*e = test
return nil
}
func main() {
kkk := "common:\n vartest1: 1.2000\n vartest2: 1.22233"
tmp := map[string]interface{}{}
yaml.Unmarshal([]byte(kkk), tmp)
fmt.Println(tmp)
}
但是UnmarshalYAML
没有被调用,因为类型Myfloat64
不在map[string]interface{}{}
中。我必须确保map[string]interface{}{}
保持不变,因为我不能有一个固定的结构来定义那个解组结构。
有没有办法保持精度?输入必须是"common:\n vartest1: 1.2000\n vartest2: 1.22233"
。不允许将1.2000更新为字符串。
英文:
I got this code:
package main
import (
"fmt"
"gopkg.in/yaml.v2"
)
func main() {
kkk := "common:\n vartest1: 1.2000\n vartest2: 1.22233"
tmp := map[string]interface{}{}
yaml.Unmarshal([]byte(kkk), tmp)
fmt.Println(tmp)
}
What I expect is the precision of float keeps the same with the string. But I got this output:
map[common:map[vartest1:1.2 vartest2:1.22233]]
I tried this:
package main
import (
"fmt"
"gopkg.in/yaml.v2"
)
type Myfloat64 float64
func (e *Myfloat64) UnmarshalYAML(unmarshal func(interface{}) error) error {
var test Myfloat64
err := unmarshal(&test)
if err != nil {
return err
}
fmt.Println(test)
*e = test
return nil
}
func main() {
kkk := "common:\n vartest1: 1.2000\n vartest2: 1.22233"
tmp := map[string]interface{}{}
yaml.Unmarshal([]byte(kkk), tmp)
fmt.Println(tmp)
}
But the UnmarshalYAML
hasn't been called as the type Myfloat64 is not in map[string]interface{}{}
. I have to ensure map[string]interface{}{}
unchanged, because I can not have a fixed struct defining that unmarshaled structure.
Is there any way to keep the precision? The input must be "common:\n vartest1: 1.2000\n vartest2: 1.22233". Updating 1.2000 to string is not allowed.
答案1
得分: 1
有没有办法保持精度?
不要将字符串解析为浮点数,而是保留原始值,即保留字符串。
这是一个示例:
- 注意1:代码需要扩展以处理其他类型。
- 注意2:这里使用的是
yaml.v3
。
type Any struct {
Val any
}
func (a Any) String() string {
return fmt.Sprint(a.Val)
}
func (a *Any) UnmarshalYAML(n *yaml.Node) error {
switch n.Kind {
case yaml.MappingNode:
m := map[string]Any{}
if err := n.Decode(&m); err != nil {
return err
}
a.Val = m
case yaml.ScalarNode:
switch n.Tag {
case "!!float":
// 不要解析原始字符串值,
// 如果要保留其格式,则直接使用它。
a.Val = n.Value
}
}
return nil
}
在playground上尝试一下。
# 输出:
map[common:map[vartest1:1.2000 vartest2:1.22233]]
英文:
> Is there any way to keep the precision?
Don't parse the string as float, instead keep the raw value, i.e. keep the string
.
Here's an example:
- note #1: the code will need to be extended for it to be able to handle other types.
- note #2: this is using
yaml.v3
type Any struct {
Val any
}
func (a Any) String() string {
return fmt.Sprint(a.Val)
}
func (a *Any) UnmarshalYAML(n *yaml.Node) error {
switch n.Kind {
case yaml.MappingNode:
m := map[string]Any{}
if err := n.Decode(&m); err != nil {
return err
}
a.Val = m
case yaml.ScalarNode:
switch n.Tag {
case "!!float":
// Don't parse the raw string value,
// use it as is if you want to retain
// its formatting.
a.Val = n.Value
}
}
return nil
}
Try it on playground.
# output:
map[common:map[vartest1:1.2000 vartest2:1.22233]]
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论