Description
I propose a simple version of string interpolation similar to that in Swift. This is a simpler version of #34174 and #50554.
Proposal
In string literals we permit a new escape sequence \(
. A valid \(
must be followed a expression and a trailing )
. Any unquoted (
in the expression must be balanced by a )
so that the compiler can locate the )
that terminates the \(
.
The expression is evaluated in the context of the string literal. If it is not valid, the compiler reports an error. Multiple \(
expressions in the string literal are evaluated from left to right.
The expression must evaluate to a single value. If the type of that value has a method String() string
, that method is called to get a string value. Otherwise the expression must be a string, integer, floating-point, complex, or boolean value. Values of other types will be reported as an error.
- If the expression has a string type, it is used as is.
- If the expression is a constant expression it is converted (as described below) to an untyped string constant.
- Otherwise the expression is converted (as described below) to a non-constant value of type
string
.
The original string "prefix\(expression)suffix"
is then replaced by the expression ("prefix" + expressionAsString + "suffix")
.
Examples
// Prints something like "Ken Thompson is 79 years old".
fmt.Println("\(person.Name()) is \(person.Age()) years old")
// Prints something like "The time is 2023-01-04 16:22:01.204034106 -0800 PST".
// Note: calls the String method of time.Time.
fmt.Println("The time is \(time.Now().Round(0))")
Formatting
Integer values are converted to strings in the obvious way.
Floating-point values are converted to strings with the equivalent of strconv.FormatFloat(f, 'g', prec, -1)
. This will need to be spelled out in the spec.
Complex values are converted to strings by converting the real and imaginary parts to R
and I
as with any float, and producing R+Ii
or R-Ii
.
Boolean values are converted to either "true"
or "false"
.
Values of other types are not permitted.
Commentary
String interpolation is useful to avoid mistakes in complex formatting, as discussed in the earlier issues.
The earlier issues were caught up in complexity due to the desire to control formatting. However, 1) we already have fmt.Sprintf
for arbitrary formatting; 2) even with simple string interpolation we can do formatting by writing code like "The average of \(len(values)) is \(strconv.FormatFloat(average, 'f', 32, 2))"
.
The syntax \(EXPR)
is borrowed from Swift.
The type of the result ensures that interpolating variable values into a string can't produce an untyped string constant, but can only produce a non-constant string value. This will avoid implicit type conversions.
This proposal is backward compatible as currently using \(
in a string causes a compilation error.