在Go模板中随机选择内容

I would like to choose a part of the generated document randomly based on the given weights, something like this pseudo-code:

{{prob 50}}
    This will appear with probability 50%.
{{prob 30}}
    This will appear with probability 30%.
{{prob 20}}
     You got the idea.
{{endprob}}

The best things that has come to my mind so far is:

{{choose . "template1" 50 "template2" 30 "template3" 20}}

where choose is my function that belongs to FuncMap. The current template is passed to itself as e.g. .T and templateN are the associated templates. The function would choose the template, look it up in .T and render with .. Another similar option would be to pass templateN as part of . directly.

I wonder if there's a more elegant / less hackish way? I guess, it's not possible to create custom actions in text/template, is it?

The standard template packages do not support custom actions.

You can get close to your proposed {{prob}}/{{endprob}} action using a function map and the built-in {{if}} action.

Convert the weights to non-overlapping ranges in [0.0,1.0). Use a random number in [0.0,1.0) to select an alternative using an if action in the template.

var t = template.Must(template.New("").
    Funcs(template.FuncMap{"rand": rand.Float64}).
    Parse(`
{{$r := rand}}
{{if le $r 0.5}}
    This will appear with probability 50%.
{{else if le $r 0.8}}
    This will appear with probability 30%.
{{else}}
     You got the idea.
{{end}}`))

playground

Here's an alternative that allows you to specify weights in the template instead of ranges:

type randPicker struct {
    n float64 // random number in  [0.0,1.0)
    t float64 // total of weights so far
}

func (rp *randPicker) Weight(w float64) bool {
    rp.t += w
    return rp.t <= rp.n
}

func newRandPicker() *randPicker {
    return &randPicker{n: rand.Float64()}
}

var t = template.Must(template.New("").
    Funcs(template.FuncMap{"rp": newRandPicker}).
    Parse(`
{{$rp := rp}}
{{if rp.Weight 0.50}}
    This will appear with probability 50%.
{{else if rp.Weight 0.30}}
    This will appear with probability 30%.
{{else}}
    You got the idea
{{end}}`))

playground