在Python中,可以执行以下操作:

"File {file} had error {error}".format(file=myfile, error=err)

或者这样:

"File %(file)s had error %(error)s" % {"file": myfile, "error": err}

在围棋中,最简单的 Select 是:

fmt.Sprintf("File %s had error %s", myfile, err)

这不允许您交换格式字符串中的参数顺序,对于I18N,您需要这样做.Go does拥有template套餐,它需要类似以下内容:

package main

import (
    "bytes"
    "text/template"
    "os"
)

func main() {
    type Params struct {
        File string
        Error string
    }

    var msg bytes.Buffer

    params := &Params{
        File: "abc",
        Error: "def",
    }

    tmpl, _ := template.New("errmsg").Parse("File {{.File}} has error {{.Error}}")
    tmpl.Execute(&msg, params)
    msg.WriteTo(os.Stdout)
}

对于错误消息来说,这似乎是一条很长的路要走.有没有更合理的选项允许我给出独立于顺序的字符串参数?

推荐答案

With strings.Replacer

使用strings.Replacer,实现你的愿望的格式化程序是非常简单和紧凑的.

func main() {
    file, err := "/data/test.txt", "file not found"

    log("File {file} had error {error}", "{file}", file, "{error}", err)
}

func log(format string, args ...string) {
    r := strings.NewReplacer(args...)
    fmt.Println(r.Replace(format))
}

输出(在Go Playground上试用):

File /data/test.txt had error file not found

我们可以通过自动将括号添加到log()函数中的参数名称来使其使用起来更舒适:

func main() {
    file, err := "/data/test.txt", "file not found"

    log2("File {file} had error {error}", "file", file, "error", err)
}

func log2(format string, args ...string) {
    for i, v := range args {
        if i%2 == 0 {
            args[i] = "{" + v + "}"
        }
    }
    r := strings.NewReplacer(args...)
    fmt.Println(r.Replace(format))
}

输出(在Go Playground上试用):

File /data/test.txt had error file not found

是的,您可以说这只接受string个参数值.这是真的.稍有改进,这就不是真的了:

func main() {
    file, err := "/data/test.txt", 666

    log3("File {file} had error {error}", "file", file, "error", err)
}

func log3(format string, args ...interface{}) {
    args2 := make([]string, len(args))
    for i, v := range args {
        if i%2 == 0 {
            args2[i] = fmt.Sprintf("{%v}", v)
        } else {
            args2[i] = fmt.Sprint(v)
        }
    }
    r := strings.NewReplacer(args2...)
    fmt.Println(r.Replace(format))
}

输出(在Go Playground上试用):

File /data/test.txt had error 666

它的一个变体接受params作为map[string]interface{},并将结果返回为string:

type P map[string]interface{}

func main() {
    file, err := "/data/test.txt", 666

    s := log33("File {file} had error {error}", P{"file": file, "error": err})
    fmt.Println(s)
}

func log33(format string, p P) string {
    args, i := make([]string, len(p)*2), 0
    for k, v := range p {
        args[i] = "{" + k + "}"
        args[i+1] = fmt.Sprint(v)
        i += 2
    }
    return strings.NewReplacer(args...).Replace(format)
}

试试Go Playground码.

With text/template

您的模板解决方案或提案也太过冗长.它可以像这样紧凑地编写(省略错误判断):

type P map[string]interface{}

func main() {
    file, err := "/data/test.txt", 666

    log4("File {{.file}} has error {{.error}}", P{"file": file, "error": err})
}

func log4(format string, p P) {
    t := template.Must(template.New("").Parse(format))
    t.Execute(os.Stdout, p)
}

输出(在Go Playground上try ):

File /data/test.txt has error 666

如果您想返回string(而不是将其打印到标准输出),您可以这样做(在Go Playground上试用):

func log5(format string, p P) string {
    b := &bytes.Buffer{}
    template.Must(template.New("").Parse(format)).Execute(b, p)
    return b.String()
}

使用显式参数索引

另一个答案中已经提到了这一点,但为了完成这一点,要知道相同的显式参数索引可以被任意次数使用,从而导致相同的参数被多次替换.阅读更多关于这个问题的信息:Replace all variables in Sprintf with same variable

Go相关问答推荐

CGO Linux到Windows交叉编译中的未知类型名称

Websocket服务器实现与x/net库trowing 403

如何解析Go-Gin多部分请求中的 struct 切片

如何使用 Go 连接到非默认 firestore 数据库?

Go time.Parse 无效的 ISO 日期

在 Golang 中查看目录是否可写的跨平台方式?

Golang 创建一个带有处理程序的模拟数据库并使用接口调用数据库

Gremlin-Go:树步骤不可序列化

如何从 Go 中的 `HijackedResponse` 中删除 Cursor Position ANSI 转义码?

使用模拟在 golang 中测试我的界面.专门测试调用同级函数的 1 个函数

如何在 Golang http.Request 对象中读取自定义 ajaxParams

整理时转换值

使用 GO 在侧 tar 文件中提取 tar 文件的最快方法

GRPC 元数据未在 Go 中更新

在 Raspberry Pi4 上下载 Go Mod

HCL 解码:具有多个标签的块

递归数据 struct 解组在 Go Lang Protobuf 中给出错误无法解析无效的线格式数据

Go:如何通过 GIN-Router 从 AWS S3 将文件作为二进制流发送到浏览器?

有没有办法在golang中映射一组对象?

Golang 查询扫描未将查询正确扫描到 struct 中