In Python, you can do this:
"File {file} had error {error}".format(file=myfile, error=err)
or this:
"File %(file)s had error %(error)s" % {"file": myfile, "error": err}
In Go, the simplest option is:
fmt.Sprintf("File %s had error %s", myfile, err)
which doesn't let you swap the order of the parameters in the format string, which you need to do for I18N. Go does have the template
package, which would require something like:
package main
import (
"bytes"
"text/template"
"os"
)
func main() {
type Params struct {
File string
Error string
}
var msg bytes.Buffer
params := &Params{
File: "abc",
Error: "def",
}
tmpl, _ := template.New("errmsg").Parse("File {{.File}} has error {{.Error}}")
tmpl.Execute(&msg, params)
msg.WriteTo(os.Stdout)
}
which seems like a long way to go for an error message. Is there a more reasonable option that allows me to give string parameters independent of order?
Alas, there's no built-in function in Go for string interpolation with named parameters (yet). But you are not the only one suffering out there :) Some packages should exist, for example: https://github.com/imkira/go-interpol . Or, if feeling adventurous, you could write such a helper yourself, as the concept is actually quite simple.
Cheers, Dennis
I don't know of any easy way of naming the parameters, but you can easily change the order of the arguments, using explicit argument indexes:
From docs:
Then you can, ie:
The parameter can also be a map, so the following function would work if you don't mind parsing every error format every time you use it:
It's still a little wordier than I would have liked, but it's better than some other options, I suppose. You could turn
map[string]interface{}
into a local type and reduce it further to:With
strings.Replacer
Using
strings.Replacer
, implementing a formatter of your desire is very easy and compact.Output (try it on the Go Playground):
We can make it more pleasant to use by adding the brackets to the parameter names automatically in the
log()
function:Output (try it on the Go Playground):
Yes, you could say that this only accepts
string
parameter values. This is true. With a little more improvement, this won't be true:Output (try it on the Go Playground):
A variant of this to accept params as a
map[string]interface{}
and return the result as astring
:Try it on the Go Playground.
With
text/template
Your template solution or proposal is also way too verbose. It can be written as compact as this (error checks omitted):
Output (try it on the Go Playground):
If you want to return the
string
(instead of printing it to the standard output), you may do it like this (try it on the Go Playground):Using explicit argument indices
This was already mentioned in another answer, but to complete it, know that the same explicit argument index may be used arbitrary number of times and thus resulting in the same parameter substituted in multiple times. Read more about this in this question: Replace all variables in Sprintf with same variable