drbfxb977777 2016-11-25 19:10
浏览 154
已采纳

等价于Go中的Python string.format?

In Python, you can do this:

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

or this:

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

In Go, the simplest option is:

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

which doesn't let you swap the order of the parameters in the format string, which you need to do for I18N. Go does have the template package, which would require something like:

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)
}

which seems like a long way to go for an error message. Is there a more reasonable option that allows me to give string parameters independent of order?

  • 写回答

4条回答 默认 最新

  • dqayok7935 2016-11-25 20:01
    关注

    With strings.Replacer

    Using strings.Replacer, implementing a formatter of your desire is very easy and compact.

    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))
    }
    

    Output (try it on the Go Playground):

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

    We can make it more pleasant to use by adding the brackets to the parameter names automatically in the log() function:

    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))
    }
    

    Output (try it on the Go Playground):

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

    Yes, you could say that this only accepts string parameter values. This is true. With a little more improvement, this won't be true:

    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))
    }
    

    Output (try it on the Go Playground):

    File /data/test.txt had error 666
    

    A variant of this to accept params as a map[string]interface{} and return the result as a 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)
    }
    

    Try it on the Go Playground.

    With text/template

    Your template solution or proposal is also way too verbose. It can be written as compact as this (error checks omitted):

    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)
    }
    

    Output (try it on the Go Playground):

    File /data/test.txt has error 666
    

    If you want to return the string (instead of printing it to the standard output), you may do it like this (try it on the Go Playground):

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

    Using explicit argument indices

    This was already mentioned in another answer, but to complete it, know that the same explicit argument index may be used arbitrary number of times and thus resulting in the same parameter substituted in multiple times. Read more about this in this question: Replace all variables in Sprintf with same variable

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

悬赏问题

  • ¥60 Python如何后台操作Vmwake虚拟机键鼠
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?
  • ¥15 c++头文件不能识别CDialog
  • ¥15 Excel发现不可读取的内容