fmt.Sprintf passing an array of arguments
Asked Answered
T

5

21

Sorry for the basic question. I'd like to pass a slice as arguments to fmt.Sprintf. Something like this:

values := []string{"foo", "bar", "baz"}
result := fmt.Sprintf("%s%s%s", values...)

And the result would be foobarbaz, but this obviously doesn't work.

(the string I want to format is more complicated than that, so a simple concatenation won't do it :)

So the question is: if I have am array, how can I pass it as separated arguments to fmt.Sprintf? Or: can I call a function passing an list of arguments in Go?

Toting answered 22/8, 2011 at 10:12 Comment(0)
L
28

As you found out on IRC, this will work:

values := []interface{}{"foo", "bar", "baz"}
result := fmt.Sprintf("%s%s%s", values...)

Your original code doesn't work because fmt.Sprintf accepts a []interface{} and []string can't be converted to that type, implicitly or explicitly.

Laurettelauri answered 22/8, 2011 at 20:40 Comment(4)
This is less practical in some use cases. For example, I'm trying to match an interface which takes a ...string argument, so I can't change the type to []interface{} without explicitly allocating a new slice and copying all of the elements over.Reproach
Yes, that's true and unfortunate. In that case you have to figure out whether it's worth the allocate-and-copy or find another solution.Laurettelauri
@EvanShaw what is the purpose of having values...?Glomma
values... is equivalent to fmt.Sprintf("%s%s%s", "foo", "bar", "baz"), while values is equivalent to fmt.Sprintf("%s%s%s", []interface{}{"foo", "bar", "baz"}). The latter is probably not what you want and will produce an error message at runtime.Laurettelauri
V
4

If the format is strictly like what you asked, then the accepted answer is indeed the way to go.

Fyi, if it is for logging purposes where you simply want to print them, then another way is by using %v

values := []string{"foo", "bar", "baz"}
result := fmt.Sprintf("%v", values)
fmt.Println(result)

result:

[foo bar baz]

Go playground: https://go.dev/play/p/_fZrT9mMmdb

Valdavaldas answered 15/6, 2022 at 14:42 Comment(0)
C
2

if not use array, use args ...any

package main

import "fmt"

func main() {
    format := "%d,%d: %s"

    check(format, 4, 5, "hello")
}

func check(format string, args ...any) {

    fmt.Printf(format, args...)
}
Clingy answered 27/2, 2023 at 9:58 Comment(0)
H
0

If it's as simple as joining array values, using Join function can be an option:

func main() {
    values := []string{"one", "two", "three"}
    fmt.Println(strings.Join(values, ""))
}

If it's more complicated, then you can have a function like this:

func PrintValues(values []string) string {
    result := ""
    for _, val := range values {
        result = fmt.Sprintf("%s%s", result, val)
    }

    return result
}

func main() {
    values := []string{"one", "two", "three"}
    fmt.Println(PrintValues(values))
}

You can change what it does in for loop

If the array is big and you have many strings to concatenate, you can use a buffer for better performance:

func PrintValues(values []string) string {
    var buffer bytes.Buffer
    for _, val := range values {
        buffer.WriteString(val)
    }

    return buffer.String()
}
Hiroshige answered 3/3, 2024 at 16:21 Comment(0)
P
-1

I think the issue with doing this is that the Sprintf won't work with unbounded length slices, so it's not practical. The number of format parameters must match the number of formatting directives. You will either have to extract them into local variables or write something to iterate the slice and concatenate the strings together. I'd go for the latter.

Poliard answered 22/8, 2011 at 11:13 Comment(3)
I got an answer on IRC: it will with values := []interface{}{"foo", "bar", "baz"}.Toting
I'm afraid on this one you are not even wrong. What is an "unbounded length slices"? There is no such thing in Go, all slices have a len() and a cap().Mixture
i.e. the length is not known at compile time. I should be more clear.Poliard

© 2022 - 2025 — McMap. All rights reserved.