簡體   English   中英

yaml:解組錯誤:無法將字符串解組為時間。Golang 中的持續時間

[英]yaml: unmarshal errors: cannot unmarshal string into time.Duration in Golang

我有如下結構:

type Connect struct {
     ClientID string `yaml:"clientid"`
     Password string `yaml:"password"`
     Timeout  time.Duration `yaml:"timeout"`
}

c1 := `
    id: 'client1'
    password: 'hhhhhhha'
    timeout: 10
    `

c2 := `
    id: 'client2'
    password: 'llllllla'
    timeout: '10'
    `

c3 := `
    id: 'client3'
    password: 'hhhhhhha'
    timeout: 10s
    `

c4 := `
    id: 'client4'
    password: 'llllllla'
    timeout: '10s'
    `

如上圖,Timeout的類型是time.Duration,默認單位是Nanosecond,但是我想得到的結果是:c1 && c2有錯誤,c3 && c4有效( Timeout的配置必須有單位)。 我應該如何重寫 yaml 的 UnmarshalYAML() 方法? 多謝。

我將在UnmarshalYAML函數中創建一個別名類型,以便所有值都可以解組為某些原始類型。 然后我將重寫那些匹配的值並轉換那些不匹配的值:

package main

import (
    "fmt"
    "time"

    "gopkg.in/yaml.v2"
)

type Connect struct {
    ClientID string        `yaml:"clientid"`
    Password string        `yaml:"password"`
    Timeout  time.Duration `yaml:"timeout"`
}

func (ut *Connect) UnmarshalYAML(unmarshal func(interface{}) error) error {
    type alias struct {
        ClientID string `yaml:"clientid"`
        Password string `yaml:"password"`
        Timeout  string `yaml:"timeout"`
    }

    var tmp alias
    if err := unmarshal(&tmp); err != nil {
        return err
    }

    t, err := time.ParseDuration(tmp.Timeout)
    if err != nil {
        return fmt.Errorf("failed to parse '%s' to time.Duration: %v", tmp.Timeout, err)
    }

    ut.ClientID = tmp.ClientID
    ut.Password = tmp.Password
    ut.Timeout = t

    return nil
}

func main() {
    c1 := `
id: 'client1'
password: 'hhhhhhha'
timeout: 10
`

    c2 := `
id: 'client2'
password: 'llllllla'
timeout: '10'
`

    c3 := `
id: 'client3'
password: 'hhhhhhha'
timeout: 10s
`

    c4 := `
id: 'client4'
password: 'llllllla'
timeout: '10s'
`

    cc := []string{c1, c2, c3, c4}
    for i, cstr := range cc {
        var c Connect
        err := yaml.Unmarshal([]byte(cstr), &c)
        if err != nil {
            fmt.Printf("Error for c%d: %v\n", (i + 1), err)
            continue
        }
        fmt.Printf("c%d: %+v\n", (i + 1), c)
    }
}

輸出如下所示:

$ go run main.go
Error for c1: failed to parse '10' to time.Duration: time: missing unit in duration10
Error for c2: failed to parse '10' to time.Duration: time: missing unit in duration10
c3: {ClientID: Password:hhhhhhha Timeout:10s}
c4: {ClientID: Password:llllllla Timeout:10s}

一種方法是為實現 Unmarshaler 接口的Timeout創建自定義類型,如果您無法在ConnectUnmarshalYAML方法中執行此操作:

type Connect struct {
     ClientID string `yaml:"clientid"`
     Password string `yaml:"password"`
     Timeout  UnmarshalingTimeout `yaml:"timeout"`
}

type UnmarshalingTimeout time.Duration 

func (ut UnmarshalingTimeout) UnmarshalYAML(unmarshal func(interface{}) error) error {
    // implement unmarshaling here
}

目前它也適用於gopkg.in/yaml.v2 ,因此接受的答案已過時

https://play.golang.org/p/lbragq1QNqD

package main

import (
    "fmt"
    "time"

    "gopkg.in/yaml.v2"

)

type Config struct {
    Timeout time.Duration `yaml:"timeout"`
}


func main() {
    sample := `
timeout: 1s
`
    var b Config
    if err := yaml.Unmarshal([]byte(sample), &b); err != nil {
        panic(err)
    }
    fmt.Printf("%+v", b)
}

的拆封time.Duration工程yaml.v3, https://play.golang.org/p/-6y0zq96gVz

package main

import (
    "fmt"
    "time"
    
    "gopkg.in/yaml.v3"
)

type Config struct {
    Timeout time.Duration `yaml:"timeout"`
}

func main() {
    var cfg Config

    b := []byte(`timeout: 60s`)
    yaml.Unmarshal(b, &cfg)
    fmt.Printf("timeout: %dm", int(cfg.Timeout.Minutes()))
}
type system struct {
    ...
    TokenLifeTime yamlTimeDur  `yaml:"TokenLifeTime"`
}

type yamlTimeDur time.Duration

func (t *yamlTimeDur) UnmarshalYAML(unmarshal func(interface{}) error) error {
    var tm string
    if err := unmarshal(&tm); err != nil {
        return err
    }

    td, err := time.ParseDuration(tm)
    if err != nil {
        return fmt.Errorf("failed to parse '%s' to time.Duration: %v", tm, err)
    }

    *t = yamlTimeDur(td)
    return nil
}

func (t *yamlTimeDur) Duration() time.Duration {
    return time.Duration(*t)
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM