Sformatować ciąg Go bez drukowania?
Proste łańcuchy
Dla „prostych” łańcuchów (zwykle to, co mieści się w wierszu) najprostszym rozwiązaniem jest użycie funkcji fmt.Sprintf()
i jej przyjaciół (fmt.Sprint()
, fmt.Sprintln()
). Są one analogiczne do funkcji bez początkowej litery S
, ale te warianty Sxxx()
zwracają wynik jako string
zamiast wypisywać go na standardowe wyjście.
Na przykład:
s := fmt.Sprintf("Hi, my name is %s and I'm %d years old.", "Bob", 23)
Zmienna s
zostanie zainicjowana wartością:
Hi, my name is Bob and I'm 23 years old.
Wskazówka: Jeśli chcesz tylko konkatenować wartości różnych typów, możesz nie potrzebować automatycznie używać Sprintf()
(który wymaga łańcucha formatu), ponieważ Sprint()
robi dokładnie to. Zobacz ten przykład:
i := 23s := fmt.Sprint("") // s will be ""
Do konkatenacji tylko string
s, możesz również użyć strings.Join()
, gdzie możesz określić niestandardowy separator string
(do umieszczenia między ciągami do połączenia).
Spróbuj tego na Go Playground.
Złożone ciągi (dokumenty)
Jeśli ciąg, który próbujesz utworzyć, jest bardziej złożony (np. wielowierszowa wiadomość e-mail), fmt.Sprintf()
staje się mniej czytelny i mniej wydajny (zwłaszcza jeśli musisz to robić wiele razy).
Do tego celu biblioteka standardowa udostępnia pakiety text/template
i html/template
. Pakiety te implementują oparte na danych szablony do generowania tekstowych danych wyjściowych. html/template
służy do generowania danych wyjściowych HTML bezpiecznych przed wstrzyknięciem kodu. Zapewnia ten sam interfejs co pakiet text/template
i powinien być używany zamiast text/template
zawsze, gdy wyjściem jest HTML.
Używanie pakietów template
w zasadzie wymaga dostarczenia statycznego szablonu w postaci wartości string
(która może pochodzić z pliku, w którym to przypadku podajesz tylko nazwę pliku), który może zawierać statyczny tekst, oraz akcji, które są przetwarzane i wykonywane, gdy silnik przetwarza szablon i generuje wyjście.
Możesz dostarczyć parametry, które są zawarte/zastąpione w statycznym szablonie i które mogą kontrolować proces generowania danych wyjściowych. Typową formą takich parametrów są wartości struct
s i map
, które mogą być zagnieżdżone.
Przykład:
Na przykład powiedzmy, że chcesz wygenerować wiadomości e-mail, które wyglądają tak:
Hi !Your account is ready, your user name is: You have the following roles assigned:, , ...
Aby wygenerować takie ciała wiadomości e-mail, mógłbyś użyć następującego szablonu statycznego:
const emailTmpl = `Hi {{.Name}}!Your account is ready, your user name is: {{.UserName}}You have the following roles assigned:{{range $i, $r := .Roles}}{{if $i}}, {{end}}{{.}}{{end}}`
I dostarczyć dane jak poniżej do jego wykonania:
data := mapinterface{}{ "Name": "Bob", "UserName": "bob92", "Roles": string{"dbteam", "uiteam", "tester"},}
Normalnie dane wyjściowe szablonów są zapisywane do io.Writer
, więc jeśli chcesz uzyskać wynik jako string
, utwórz i zapisz do bytes.Buffer
(który implementuje io.Writer
). Wykonanie szablonu i uzyskanie wyniku jako string
:
t := template.Must(template.New("email").Parse(emailTmpl))buf := &bytes.Buffer{}if err := t.Execute(buf, data); err != nil { panic(err)}s := buf.String()
To spowoduje oczekiwane wyjście:
Hi Bob!Your account is ready, your user name is: bob92You have the following roles assigned:dbteam, uiteam, tester
Wypróbuj to na Go Playground.
Zauważ również, że od Go 1.10 dostępna jest nowsza, szybsza, bardziej wyspecjalizowana alternatywa dla bytes.Buffer
, która jest: strings.Builder
. Użycie jest bardzo podobne:
builder := &strings.Builder{}if err := t.Execute(builder, data); err != nil { panic(err)}s := builder.String()
Spróbuj tego na Go Playground.
Uwaga: możesz również wyświetlić wynik wykonania szablonu, jeśli podasz os.Stdout
jako cel (który również implementuje io.Writer
):
t := template.Must(template.New("email").Parse(emailTmpl))if err := t.Execute(os.Stdout, data); err != nil { panic(err)}
To zapisze wynik bezpośrednio do os.Stdout
. Wypróbuj to na Go Playground.