TheRealFakeNews
TheRealFakeNews

Reputation: 8153

How to insert a variable in to a multiline (backtick) string in Go?

I am trying to insert a variable in to a string that I pass in to a byte array. What I want is something like this:

myLocation := "foobar123"
rawJSON := []byte(`{
        "level": "debug",
        "encoding": "json",
        // ... other stuff
        "initialFields": {"location": ${myLocation} },
    }`)

I know that's not possible in Go as I've taken that from JS, but I would like to do something like that.


Working with @TheFool's answer I have done this:

    config := fmt.Sprintf(`{
        "level": "debug",
        "encoding": "json",
        "initialFields": {"loggerLocation": %s },
    }`, loggerLocation)
    rawJSON := []byte(config)

Upvotes: 4

Views: 13776

Answers (2)

ton
ton

Reputation: 4587

I understand that templates power is in reuse, think about it when using this, but for simple usecases, like commandline tools, this works fine:

func STprint(templateText string, funcMap template.FuncMap) string {
    var template = template.New("genericTemplate")
    t, _ := template.Parse(templateText)
    var buff bytes.Buffer
    t.Execute(&buff, funcMap)
    return buff.String()
}

You can use it with:

text := STprint(`{
    "level": "{{ .level }}",
    "level2": "{{ .level }}",
    "encoding": "json",
    // ... other stuff
    "initialFields": { "location": "{{ .location }}" },
}`,
        template.FuncMap{
            "level":    "INFO",
            "location": "http://google.com",
        })

https://go.dev/play/p/727fGxX4yZY

I am sure there is room for improvement.

Upvotes: 0

The Fool
The Fool

Reputation: 20467

You can use any kind of printf. For example Sprintf.

package main

import "fmt"

func main() {
    myLocation := "foobar123"
    rawJSON := []byte(`{
    "level": "debug",
    "encoding": "json",
    // ... other stuff
    "initialFields": { "location": "%s" },
}`)
    // get the formatted string 
    s := fmt.Sprintf(string(rawJSON), myLocation)
    // use the string in some way, i.e. printing it
    fmt.Println(s) 
}

For more complex templates, you can also use the templates package. With that you can use some functions and other kinds of expressions, similar to something like jinja2.

package main

import (
    "bytes"
    "fmt"
    "html/template"
)

type data struct {
    Location string
}

func main() {
    myLocation := "foobar123"
    rawJSON := []byte(`{
    "level": "debug",
    "encoding": "json",
    // ... other stuff
    "initialFields": { "location": "{{ .Location }}" },
}`)

    t := template.Must(template.New("foo").Parse(string(rawJSON)))
    b := new(bytes.Buffer)
    t.Execute(b, data{myLocation})
    fmt.Println(b.String())
}

Note, that there are 2 different templates packages html/template and text/template. The html one is stricter, for safety purposes. If you get the input from untrusted sources, it's probably wise to opt for the html one.

Upvotes: 9

Related Questions