英文:
Using methods with multiple return values
问题
我正在尝试编写一个模板(使用html/template),并将一个附带有一些方法的结构体传递给它,其中许多方法返回多个值。有没有办法在模板内部访问这些值?我想能够像这样做:
package main
import (
"fmt"
"os"
"text/template"
)
type Foo struct {
Name string
}
func (f Foo) Baz() (int, int) {
return 1, 5
}
const tmpl = `Name: {{.Name}}, Ints: {{$a, $b := .Baz}}{{$a}}, {{$b}}`
func main() {
f := Foo{"Foo"}
t, err := template.New("test").Parse(tmpl)
if err != nil {
fmt.Println(err)
}
t.Execute(os.Stdout, f)
}
但显然这样是行不通的。没有办法绕过这个问题吗?
我考虑在我的代码中创建一个匿名结构体:
data := struct {
Foo
a int
b int
}{
f,
0,
0,
}
data.a, data.b = f.Baz()
然后将其传递进去,但我更希望在模板中有一些解决方案。有什么想法吗?我还尝试编写了一个包装函数,将其添加到funcMaps中,但始终无法使其正常工作。
感谢任何建议!
英文:
I'm trying to write a template (using html/template) and passing it a struct that has some methods attached to it, many of which return multiple values. Is there any way of accessing these from within the template? I'd like to be able to do something like:
package main
import (
"fmt"
"os"
"text/template"
)
type Foo struct {
Name string
}
func (f Foo) Baz() (int, int) {
return 1, 5
}
const tmpl = `Name: {{.Name}}, Ints: {{$a, $b := .Baz}}{{$a}}, {{b}}`
func main() {
f := Foo{"Foo"}
t, err := template.New("test").Parse(tmpl)
if err != nil {
fmt.Println(err)
}
t.Execute(os.Stdout, f)
}
But obviously this doesn't work. Is there no way around it?
I've considered creating an anonymous struct in my code:
data := struct {
Foo
a int
b int
}{
f,
0,
0,
}
data.a, data.b = f.Baz()
And passing that in, but would much prefer to have something in the template. Any ideas? I also tried writing a wrapper function which I added to funcMaps but could never get that to work at all.
Thanks for any suggestions!
答案1
得分: 6
在模板中,除非其中一个返回值是错误,否则无法调用返回两个值的函数。这样可以确保模板在运行时正常工作。如果你感兴趣,这里有一个很好的答案解释了这个问题(链接:https://stackoverflow.com/a/28233172/555017)。
要解决你的问题,你需要采取以下两种方法之一:1)将函数拆分为两个独立的获取函数,在模板中适当的位置调用它们;或者2)让函数返回一个包含这些值的简单结构体。
我无法确定哪种方法对你来说更好,因为我不知道你的具体实现需要什么。Foo和Baz并没有给出太多线索。;)
这里是一个简单的示例,演示了第一种方法:
type Foo struct {
Name string
}
func (f Foo) GetA() (int) {
return 1
}
func (f Foo) GetB() (int) {
return 5
}
然后相应地修改模板:
const tmpl = `Name: {{.Name}}, Ints: {{.GetA}}, {{.GetB}}`
希望这对你有所帮助。:)
英文:
You won't be able to call a function that returns two values in a template unless one of those values is an error. This is so that your template is guaranteed to work at runtime. There is a great answer that explains that here, if you're interested.
To solve your problem you need to either 1) break your function into two separate getter functions that you can call in the appropriate place in your template; or 2) have your function return a simple struct with the values inside.
I can't tell which would be better for you because I really have no idea what your implementation requires. Foo and Baz don't give many clues.
Here is a quick-n-dirty example of option one:
type Foo struct {
Name string
}
func (f Foo) GetA() (int) {
return 1
}
func (f Foo) GetB() (int) {
return 5
}
And then modify the template accordingly:
const tmpl = `Name: {{.Name}}, Ints: {{.GetA}}, {{.GetB}}`
Hopefully this is of some help.
答案2
得分: 2
还有一种可能性是返回具有多个字段的结构体并使用它们。
type Result struct {
First string
Second string
}
func GetResult() Result {
return Result{First: "first", Second: "second"}
}
然后在模板中使用
{{$result := GetResult}}
{{$result.First}} - {{$result.Second}}
英文:
There is also possibility to return struct with multiple fields and use them.
type Result struct {
First string
Second string
}
func GetResult() Result {
return Result{First: "first", Second: "second"}
}
And then use in template
{{$result := GetResult}}
{{$result.First}} - {{$result.Second}}
答案3
得分: 0
我最近遇到了一个类似的问题,并找到了这个问题。我认为这可能更简洁一些。它不需要你创建多个新函数:
const tmpl = `Name: {{.Name}}, Ints: {{BazWrapper .}}`
func main() {
f := Foo{"Foo"}
funcMap := template.FuncMap{
"BazWrapper": func(f Foo) string {
a, b := f.Baz()
return fmt.Sprintf("%d, %d", a, b)
},
}
t, err := template.New("test").Funcs(funcMap).Parse(tmpl)
if err != nil {
fmt.Println(err)
}
t.Execute(os.Stdout, f)
}
英文:
I recently had a problem similar to this one and came across this question. I think this might be a little cleaner. It doesn't require you to create multiple new functions:
const tmpl = `Name: {{.Name}}, Ints: {{BazWrapper .}}`
func main() {
f := Foo{"Foo"}
funcMap := template.FuncMap{
"BazWrapper": func(f Foo) string {
a, b := f.Baz()
return fmt.Sprintf("%d, %d", a, b)
},
}
t, err := template.New("test").Funcs(funcMap).Parse(tmpl)
if err != nil {
fmt.Println(err)
}
t.Execute(os.Stdout, f)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论