使用golang模板打印以逗号和“或”分隔的列表

It is already elsewhere discussed on stackoverflow that you can print a list separated by comma, as follows:

{{ range $index, $element := .TeamMembers}}
    {{if $index}},{{end}}
    {{$element.Name}}
{{end}}

Is there an easy solution for when you need a list separator that is different for the last item, to include an "or":

{name}, {name}, {name}, or {name}

This is to allow, for example, creation of formatted sentences such as:

The members of this team are Bob, Jane, and Mike.

Any template code I can workout ends up extremely verbose and complicated.

Export a function to your template.

text/template, like some other template systems, doesn't try be good for programming in directly; it just provides a better way to stitch your data and functions with your markup, and you need to write other presentational code when it's insufficient. You can write a yourapp/template module that exports a version of New() that calls Funcs() to add the common functions you use.

(You might find uses for a lot more functions than just these; Django, for example, offers lots of builtins for pluralization, formatting, i18n, etc., and folks still often extend the set.)

package main // package mytemplate

import (
    "fmt"
    "os"
    "strings"
    "text/template"
)

func conjoin(conj string, items []string) string {
    if len(items) == 0 {
        return ""
    }
    if len(items) == 1 {
        return items[0]
    }
    if len(items) == 2 { // "a and b" not "a, and b"
        return items[0] + " " + conj + " " + items[1]
    }

    sep := ", "
    pieces := []string{items[0]}
    for _, item := range items[1 : len(items)-1] {
        pieces = append(pieces, sep, item)
    }
    pieces = append(pieces, sep, conj, " ", items[len(items)-1])

    return strings.Join(pieces, "")
}

// if you use some funcs everywhere have some package export a Template constructor that makes them available, like this:

var commonFuncs = template.FuncMap{
    "andlist": func(items []string) string { return conjoin("and", items) },
    "orlist":  func(items []string) string { return conjoin("or", items) },
}

func New(name string) *template.Template {
    return template.New(name).Funcs(commonFuncs)
}

func main() {
    // test conjoin
    fmt.Println(conjoin("or", []string{}))
    fmt.Println(conjoin("or", []string{"Bob"}))
    fmt.Println(conjoin("or", []string{"Bob", "Mike"}))
    fmt.Println(conjoin("or", []string{"Bob", "Mike", "Harold"}))

    people := []string{"Bob", "Mike", "Harold", "Academy Award nominee William H. Macy"}
    data := map[string]interface{}{"people": people}
    tmpl, err := New("myyy template").Parse("{{ orlist .people }} / {{ andlist .people }}")
    if err != nil {
        fmt.Println("sadness:", err.Error())
        return
    }
    err = tmpl.Execute(os.Stdout, data)
    if err != nil {
        fmt.Println("sadness:", err.Error())
        return
    }
}

Here's a variation that also exports "conjoin", and an "isLast" function you can use in a kind of verbose construction to do some arbitrary thing differently in the last go through the loop.

For the "creation of a proper English formatted sentence" from a list use a function.

Your plural example is

The members of this team are Bob, Jane, and Mike.

What is your singular example where there is only one element in the list? For example,

The only member of this team is Bob.

What is your empty example when there are no elements in the list? For example,

There are no members of this team.

Creating proper English sentences and paragraphs from a mail merge is hard.