C# syntax (Interpolated Strings?)

One thing that I really liked in C# was the way you could write:

int age = 80;
string s = $"I am {age} years old.";

Is there a package for Go that can do something similar? Does fmt support a similar syntax? I am of course aware of the syntax below, but it is a little bit longer and not as “pretty” in my opinion. Especially when you have multiple arguments:

age:=80
s:=fmt.Sprintf("I am %d years old.", age)
2 Likes

The nearest one could be one of the below, no idea if there is a fifth way (or more), considering 3 here plus your way, total is 4:

package main

import (
	"fmt"
	"strconv"
	"strings"
)

func main() {
	age := 80
	s1 := fmt.Sprint("I am ", age, "  years old.")
    // or Sprintln to insert space automatically before and after the fields  
    s := fmt.Sprintln("I am", age, "years old.")
	s2 := "I am " + strconv.Itoa(age) + "  years old."
	s3 := strings.Join([]string{"I am", strconv.Itoa(age), "years old."}, " ")
	fmt.Println(s1)
	fmt.Println(s2)
	fmt.Println(s3)
}
1 Like

Thank you, for your suggestions.

To be honest though, the only one that I would say MAYBE looks better than the one I suggested is the first one of your suggestions (s1). It does put the argument in it’s correct position at least. I still don’t think however that solution is as clean as the C# one.

And, I didn’t mention this in my original question, but in C# you can also provide formatting settings like this:

float age = 80.5345;
string s = $"I am {age:0.##} years old.";

which would print out “I am 80.53 years old.”. This makes it even more powerful. The only way I know how to do this in Go would be with my original “solution” though, but then we are back where we started, and the variable age is out of position again.

age:=80.5345
s:=fmt.Sprintf("I am %.2f years old.", age)

I would be surprised if no one have developed a package for something similar to the C# syntax though.

I just found this link:


Obviously it has been proposed as a language extension, it might show up in the future, I guess.

1 Like

The best match I could found, though it may not be elegant, is:

package main

import (
	"fmt"
)

func main() {
	age := 80.5345
	s := fmt.Sprintln("I am", fmt.Sprintf("%0.2f", age), "years old.")
	fmt.Println(s)
}

Or may you like writing own function, as:

package main

import (
	"fmt"
)

func main() {
	age := 80.5345
	s := fmt.Sprintln("I am", interpolate("%0.2f", age), "years old.")
	fmt.Println(s)
}

func interpolate(f string, s float64) string {
	return fmt.Sprintf(f, s)
}
1 Like

C# compilers typically translate $"Hello, {whom}!"; into String.Format("Hello {0}!", whom); or String.Concat("Hello, ", whom, "!"); (link). I’m not sure how you could do this in Go with a library; you need support from the compiler. You could use the go/* packages to write a go:generate program that can translate interpolated strings into similar calls to fmt.Sprintf or strings.Join.

2 Likes

Yeah, that sounds correct, now that I am thinking about it. Guess I’ll have to wait, and see if it will ever gets implemented. At least they are thinking about it (see my link above).

1 Like

this is new for me (I’m new for GO), do you have a link that I can learn from, or shall I google it :slight_smile:

I highly recommend checking out the source code for stringer which generates String functions for the types you give it.

Shameless plug, but I think it’s relevant: I adapted the source code for stringer to generate a plugin-like API for accessing constants, global variables, functions, and types by their name so you could do, for example:

package main

import "github.com/skillian/pkgsyms"

//go:generate pkgsyms -package "fmt"

var fmtPkg = pkgsyms.Of("fmt")

func main() {
    fmtPkg.Lookup("Println").Value.(func(args ...interface{}) (int, error))("hello, world!")
}

I’m doing this from my phone, so I’m not certain that the code above even compiles, and this isn’t really the point, of course. It’s more to let me write type names in configuration files so Ican implement dependency injection for some other project I’m working on, but I digress!

My point is that you can look at the source code of stringer and compare it to pkgsyms to see the kind of things you have to change to handle reading Go source code files. Both stringer and pkgsyms do some string formatting to generate separate output files. They don’t transform the actual input source code which you would probably have to do if you wanted to implement string interpolation. For that, you’d have to use the astutil package. Unfortunately, I can’t help you out with any examples right now because I have never used that package.