Een Go-tekenreeks formatteren zonder af te drukken?
Eenvoudige tekenreeksen
Voor “eenvoudige” tekenreeksen (meestal wat in een regel past) is de eenvoudigste oplossing het gebruik van fmt.Sprintf()
en vrienden (fmt.Sprint()
, fmt.Sprintln()
). Deze zijn analoog aan de functies zonder de beginletter S
, maar deze Sxxx()
varianten geven het resultaat terug als een string
in plaats van ze af te drukken naar de standaarduitvoer.
Voorbeeld:
s := fmt.Sprintf("Hi, my name is %s and I'm %d years old.", "Bob", 23)
De variabele s
zal worden geïnitialiseerd met de waarde:
Hi, my name is Bob and I'm 23 years old.
Tip: Als u alleen waarden van verschillende typen wilt samenvoegen, hoeft u niet automatisch Sprintf()
te gebruiken (die een format string vereist), aangezien Sprint()
precies dit doet. Zie dit voorbeeld:
i := 23s := fmt.Sprint("") // s will be ""
Voor het aaneenschakelen van alleen string
s, kunt u ook strings.Join()
gebruiken, waar u een aangepast scheidingsteken string
kunt opgeven (dat tussen de aan te sluiten strings moet worden geplaatst).
Probeer deze op de Go Playground.
Complexe strings (documenten)
Als de string die u probeert te maken complexer is (bijvoorbeeld een e-mail bericht van meerdere regels), wordt fmt.Sprintf()
minder leesbaar en minder efficiënt (vooral als u dit vele malen moet doen).
Voor dit doel biedt de standaard bibliotheek de pakketten text/template
en html/template
. Deze pakketten implementeren data-driven sjablonen voor het genereren van tekstuele output. html/template
is voor het genereren van HTML-uitvoer die veilig is tegen code-injectie. Het biedt dezelfde interface als pakket text/template
en moet worden gebruikt in plaats van text/template
wanneer de output HTML is.
Het gebruik van de template
pakketten vereist in feite dat u een statisch sjabloon in de vorm van een string
waarde (die kan afkomstig zijn van een bestand in welk geval u alleen de bestandsnaam verstrekt) die statische tekst kan bevatten, en acties die worden verwerkt en uitgevoerd wanneer de motor het sjabloon verwerkt en de output genereert.
U kunt parameters opgeven die in het statische sjabloon worden opgenomen/vervangen en die het proces voor het genereren van de uitvoer kunnen regelen. Typische vorm van dergelijke parameters zijn struct
s en map
-waarden die mogen worden genest.
Voorbeeld:
Zo wilt u bijvoorbeeld e-mailberichten genereren die er als volgt uitzien:
Hi !Your account is ready, your user name is: You have the following roles assigned:, , ...
Om e-mailberichtlichamen als deze te genereren, zou u het volgende statische sjabloon kunnen gebruiken:
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}}`
En de volgende gegevens verstrekken om het uit te voeren:
data := mapinterface{}{ "Name": "Bob", "UserName": "bob92", "Roles": string{"dbteam", "uiteam", "tester"},}
Normaal gesproken wordt de uitvoer van sjablonen geschreven naar een io.Writer
, dus als u het resultaat als een string
wilt, moet u een bytes.Buffer
maken en schrijven naar een bytes.Buffer
(die io.Writer
implementeert). Het uitvoeren van het sjabloon en het verkrijgen van het resultaat als 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()
Dit zal resulteren in de verwachte output:
Hi Bob!Your account is ready, your user name is: bob92You have the following roles assigned:dbteam, uiteam, tester
Probeer het op de Go Playground.
Merk ook op dat sinds Go 1.10, een nieuwer, sneller, meer gespecialiseerd alternatief beschikbaar is voor bytes.Buffer
en dat is: strings.Builder
. Het gebruik is zeer vergelijkbaar:
builder := &strings.Builder{}if err := t.Execute(builder, data); err != nil { panic(err)}s := builder.String()
Probeer deze eens op de Go Playground.
Note: je kunt ook het resultaat van een template executie laten zien als je os.Stdout
als doel opgeeft (die ook io.Writer
implementeert):
t := template.Must(template.New("email").Parse(emailTmpl))if err := t.Execute(os.Stdout, data); err != nil { panic(err)}
Dit zal het resultaat direct naar os.Stdout
schrijven. Probeer dit op de Go Playground.