在不打印的情况下格式化 Go 字符串?

新手上路,请多包涵

有没有一种简单的方法可以在不打印字符串的情况下在 Go 中格式化字符串?

我可以:

 bar := "bar"
fmt.Printf("foo: %s", bar)

但我希望返回而不是打印格式化字符串,以便我可以进一步操作它。

我也可以这样做:

 s := "foo: " + bar

但是,当格式字符串很复杂时,这会变得难以阅读,并且当一个或多个部分不是字符串并且必须先进行转换时,这会很麻烦,比如

i := 25
s := "foo: " + strconv.Itoa(i)

有没有更简单的方法来做到这一点?

原文由 Carnegie 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 542
2 个回答

Sprintf 是您正在寻找的。

例子

fmt.Sprintf("foo: %s", bar)

您还可以在“Go 之旅”的 错误示例 中看到它的使用。

 return fmt.Sprintf("at %v, %s", e.When, e.What)

原文由 Sonia 发布,翻译遵循 CC BY-SA 4.0 许可协议

1. 简单字符串

对于“简单”字符串(通常适合一行),最简单的解决方案是使用 fmt.Sprintf() 和朋友( fmt.Sprint()fmt.Sprintln() )。这些类似于没有启动器的函数 S 字母,但是这些 Sxxx() 变体将结果作为 string 返回到标准输出。

例如:

 s := fmt.Sprintf("Hi, my name is %s and I'm %d years old.", "Bob", 23)

变量 s 将初始化为以下值:

 Hi, my name is Bob and I'm 23 years old.

提示: 如果您只想连接不同类型的值,您可能不会自动需要使用 Sprintf() (这需要格式字符串),因为 Sprint() 正是这样做的。看这个例子:

 i := 23
s := fmt.Sprint("[age:", i, "]") // s will be "[age:23]"

仅用于连接 string s,您还可以使用 strings.Join() ,您可以在其中指定自定义分隔符 string (要加入的字符串之间)。

Go Playground 上试试这些。

2. 复杂字符串(文档)

如果您尝试创建的字符串更复杂(例如,多行电子邮件消息), fmt.Sprintf() 变得可读性差且效率低(尤其是当您必须多次执行此操作时)。

为此,标准库提供了包 text/templatehtml/template 。这些包实现了用于生成文本输出的数据驱动模板。 html/template 用于生成对代码注入安全的 HTML 输出。它提供与包 text/template 相同的接口,并且应该在输出为 HTML 时代替 text/template 使用。

使用 template 包基本上需要您以 string 值的形式提供静态模板(它可能源自文件,在这种情况下您只提供文件名)可能包含静态文本和引擎处理模板并生成输出时处理和执行的操作。

您可以提供静态模板中包含/替换的参数,这些参数可以控制输出生成过程。此类参数的典型形式是 struct s 和 map 可以嵌套的值。

例子:

例如,假设您要生成如下所示的电子邮件:

 Hi [name]!

Your account is ready, your user name is: [user-name]

You have the following roles assigned:
[role#1], [role#2], ... [role#n]

要生成这样的电子邮件正文,您可以使用以下静态模板:

 const emailTmpl = `Hi {{.Name}}!

Your account is ready, your user name is: {{.UserName}}

You have the following roles assigned:
{{range $i, $r := .Roles}}{{if $i}}, {{end}}{{.}}{{end}}
`

并提供这样的数据来执行它:

 data := map[string]interface{}{
    "Name":     "Bob",
    "UserName": "bob92",
    "Roles":    []string{"dbteam", "uiteam", "tester"},
}

通常模板的输出被写入 io.Writer ,所以如果你想要结果为 string ,创建并写入 bytes.Buffer io.Writer )。执行模板并得到结果 string

 t := template.Must(template.New("email").Parse(emailTmpl))
buf := &bytes.Buffer{}
if err := t.Execute(buf, data); err != nil {
    panic(err)
}
s := buf.String()

这将产生预期的输出:

 Hi Bob!

Your account is ready, your user name is: bob92

You have the following roles assigned:
dbteam, uiteam, tester

Go Playground 上尝试一下。

另请注意,自 Go 1.10 以来,可以使用更新、更快、更专业的替代方案 bytes.Buffer 即: strings.Builder 。用法非常相似:

 builder := &strings.Builder{}
if err := t.Execute(builder, data); err != nil {
    panic(err)
}
s := builder.String()

Go Playground 试试这个。

注意:如果您提供 os.Stdout 作为目标(它也实现了 io.Writer ),您也可以显示模板执行的结果:

 t := template.Must(template.New("email").Parse(emailTmpl))
if err := t.Execute(os.Stdout, data); err != nil {
    panic(err)
}

这会将结果直接写入 os.Stdout 。在 Go Playground 上试试这个。

原文由 icza 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题