2013-09-10 34 views
1

我有值的map,看起來像這樣:迭代通過地圖圍棋文本模板

vals := map[string]interface{}{"foo": 1, "bar": 2, "baz": 7} 
data := map[string]interface{}{"bat": "obj", "values": vals} 

我應該我的模板模樣生成以下字符串(注意正確使用逗號)?

SET obj.foo=1, obj.bar=2, obj.baz=7 

我開始用這個作爲我的模板:

SET {{range $i, $v := .values}} {{.bat}}.{{$i}}={{$v}},{{end}} 

但是,這僅僅打印出

SET 

而且即使沒有工作,逗號是不正確的。然後我嘗試使用自定義函數來格式化地圖,但是我無法讓模板調用我的函數。以下的無似乎工作:

SET {{.MyFunction .values}} 
SET {{call .MyFunction .values}} 
SET {{call MyFunction .values}} 

時MyFunction的定義爲:

func MyFunction(data map[string]interface{}) string { 
    fmt.PrintLn('i was called!') 
    return "foo" 
} 

而且我使用一個輔助函數,看起來像這樣執行的模板:

func useTemplate(name string, data interface{}) string { 
    out := new(bytes.Buffer) 
    templates[name].Execute(out, data) 
    return string(out.Bytes()) 
} 

謝謝!

回答

3

這將讓你相當接近:

SET {{range $key, $value := $.values}}{{$.bat}}.{{$key}}={{$value}} {{end}} 

渲染爲:

SET obj.bar=2 obj.baz=7 obj.foo=1 

不幸的是,我不認爲有什麼簡單的辦法有逗號因值之間加入range動作如何在地圖上迭代(沒有數字索引)。也就是說,template包意味着易於擴展,因此您的模板中可以擁有更少的邏輯,Go本身可以擁有更多的邏輯,因此在Go中編寫輔助函數並將其提供給模板非常簡單。

如果您很高興再多加一分,那麼模板變得更簡單,而且效率更高。該函數可以是這樣的:

func commaJoin(prefix string, m map[string]interface{}) string { 
    var buf bytes.Buffer 
    first := true 
    for k, v := range m { 
     if !first { 
      buf.WriteString(", ") 
     } 
     first = false 
     buf.WriteString(prefix) 
     buf.WriteByte('.') 
     buf.WriteString(k) 
     buf.WriteByte('=') 
     buf.WriteString(fmt.Sprint(v)) 
    } 
    return buf.String() 
} 

和您的範本看起來像:

SET {{$.values | commaJoin $.bat}} 

這裏是這個邏輯的工作示例:

+0

啊,所以這就是你如何以正確的方式調用函數。完美的作品,謝謝! – Bill

+0

@Gustavo,在這裏使用管道而不是簡單的函數調用有什麼好處?我建議使用'SET {{commaJoin $ .bat $ .values}}',恕我直言,它更容易理解。 – Kluyg

+0

我傾向於將格式化邏輯寫爲流水線,因爲似乎更容易發現正在格式化的內容,但這確實是一種偏好問題。 –