How can I join strings in Go template without template functions? - go

I have a string slice, like x := []string{a,b,c}, and eventually I want it to be like a+"/"+b+"/"+c.
The problem I'm trying to deal with is coming from the Go template.
I want to have a solution in Go template.
The following is my current solution, but it's obviously ugly.
res := {{range item := .x}}item+"/"{{end}}
res = res[:len(res)-1]
If you have better approaches, appreciate it!

Use the following code to join a slice with /:
{{range $i, $v := .x}}{{if $i}}/{{end}}{{$v}}{{end}}
Run the example on the playground.

Related

Go Template compare if string ends in or contains another string

The eq function allows for comparing if two strings are equal
{{if eq .Name "MyName"}}
Is there a way to test if a string ends in (or contains) another string?
Use a function map containing the relevant string functions.
funcs := map[string]any{
"contains": strings.Contains,
"hasPrefix": strings.HasPrefix,
"hasSuffix": strings.HasSuffix}
tmpl := `{{if hasSuffix . ".txt"}}yes!{{end}}`
t := template.Must(template.New("").Funcs(funcs).Parse(tmpl))
t.Execute(os.Stdout, "example.txt") // writes yes! to standard out
Run the example on the playground.
Some applications that use Go templates as a feature (Hugo and Helm are examples) provide these functions by default.
(h/t to mkopriva).

How can I range a slice of array in go template?

For example, I want to range Fields except the last one element.
Maybe like:
{{range $Field := $.Fields[:len $Field - 1]}}
Do I have some approaches?
Thx!
The builtin template slice function almost does what you need. The missing piece is computing the last index of the new slice. To do that, add an addition function to the template:
func add(a, b int) int {
return a + b
}
Add the function to template before parsing:
t, err := template.New(name).Funcs(template.FuncMap{"add": add}).Parse(text)
Use the function like this:
{{range slice $ 0 (add (len $) -1)}}
{{.}}
{{end}}
playground example.

Golang - printing the content of the variable

I am new to Golang and I am wondering how can I print the actual values of a struct that doc.Find() returns. I am using this package that has this methods.
So, for example if I do this:
casesCounter := doc.Find(".cases-counter li")
fmt.Printf("%T\n", casesCounter)
fmt.Println(&casesCounter)
fmt.Println(casesCounter)
I have also tried with using the pointer:
casesCounter := *doc.Find(".cases-counter li")
For each case I got memory addresses printed:
&{[0xc0004108c0 0xc000410b60] 0xc00023f720 0xc000230150}
{[0xc0004108c0 0xc000410b60] 0xc00023f720 0xc000230150}
But, how can I get the actual values of this struct, same as I when I would do console.log() in javascript?
From the documentation, calling
doc.Find(selector string)
returns a pointer to the selection
You should therefore access the data through the selection, whose structure is documented here
I suppose you want to access the nodes, and as Latif mentioned, this can be done via a loop, as this is an array as documented above
for _, v := range casesCounter.Nodes {
fmt.Printf("%+v", v)
}
You should try the following code:
for _, v := range casesCounter.Nodes {
fmt.Printf("%+v", v)
}

Why does the compiler complain about an unused variable in this instance (when it is used by fmt.Fprintf)?

I have a simple piece of code where I want to convert elements of a slice into json and then print them out to my http.responseWriter.
for _, element := range customers {
result, _ := json.Marshal(element)
fmt.Fprintf(w, string(result))
}
However when I compile this I get the error "result declared and not used". If I add a simple line:
_ = result
Then everything compiles and works fine. Why does the compiler complain about this usage, and what is the correct way to do this in go?
Any insight is appreciated, my searches so far seem to indicate the call to Fprintf should count as a usage.
The code in question does not result in the error posted, for proof, check it on the Go Playground.
This error usually is (and the op confirmed it is too in this case) caused by having a local variable with same name outside of the block, and when using the short variable declaration, that shadows that variable.
This error can be reproduced with the following code:
var result []byte
customers := []int{}
w := os.Stdout
for _, element := range customers {
result, _ := json.Marshal(element)
fmt.Fprintf(w, string(result))
}
Attempting to compile and run it, we get the error (try it on the Go Playground):
prog.go:10:6: result declared and not used
Solution is to use a simple assignment instead of the short variable declaration if intention is to use the existing variable (in which case no new variable will be created), or use a different name for the variable if intention is not to use the outer, existing variable (but then the outer variable is to be removed or be used of course).

Go templates range loop is quoting my value

I've got a slice of strings (.Table.PKey.Columns) that I'm trying to loop over in my template to generate a go file that does some appends, but when I output $value in my template, apparently Go is quoting it for me, so it is giving me the error:
5:27: expected selector or type assertion, found 'STRING' "ID"
i.e., instead of the template output looking something like o.ID -- which is what I'm aiming for, it ends up looking something like o."ID" (I presume).
Am I right in my assumption that this is the result of using a range loop? Because it seems when I access variables directly in other places (for example, say I had a string and I did: o.{{.Table.MyString}}) it works fine, but as soon as I try and incorporate a range loop into the mix it seems to be quoting things.
{{- range $key, $value := .Table.PKey.Columns }}
args = append(args, o.{{$value}})
{{ end -}}
Any suggestions? Thank you.
The {{range}} does not quote anything. If you see "ID" in your output, then your input value is "ID" with quotation marks included!
See this example:
func main() {
m := map[string]interface{}{
"Id": "Id1",
"Quoted": `"Id2"`,
"Ids": []string{"Id1", `"Id2"`, "Abc"},
}
t := template.Must(template.New("").Parse(src))
t.Execute(os.Stdout, m)
}
const src = `{{.Id}} {{index .Ids 0}} {{.Quoted}}
{{range $key, $value := .Ids}}{{$value}}
{{end}}
`
Output (try it on the Go Playground):
Id1 Id1 "Id2"
Id1
"Id2"
Abc
If the variable Go Template is rendering is within tags, then Go Template will wrap any strings with quotes for you.
Some options include generating the in code prior to asking Go Template to render it.

Resources