我有这个结构:

1
2
3
4
5
6
7
8
9
const (
    paragraph_hypothesis = 1<<iota
    paragraph_attachment = 1<<iota
    paragraph_menu       = 1<<iota
)

type Paragraph struct {
    Type int // paragraph_hypothesis or paragraph_attachment or paragraph_menu
}

我想以Type依赖的方式显示我的段落。

我发现的唯一解决方案是基于专用功能,例如isAttachment在Go中测试Type并嵌套{{if}}

1
2
3
4
5
6
7
8
9
{{range .Paragraphs}}
    {{if .IsAttachment}}
        -- attachement presentation code  --
    {{else}}{{if .IsMenu}}
        -- menu --
    {{else}}
        -- default code --
    {{end}}{{end}}
{{end}}

实际上,我有更多的类型,这使其变得更加奇怪,使用IsSomething函数的Go代码和使用那些{{end}}的模板都变得混乱。

什么是干净的解决方案? Go模板中是否存在某些switchif/elseif/else解决方案? 还是完全不同的方式来处理这些案件?

  • 您是指html模板吗? 您的Paragraph类型示例不太清楚。 通常,您可以通过向FuncMap(golang.org/pkg/text/template/#Template.Funcs)添加功能来创建自定义模板行为。 抱歉,我不确定您要做什么。

模板是无逻辑的。他们不应该具有这种逻辑。您可以拥有的最大逻辑是一堆if

在这种情况下,您应该这样做:

1
2
3
4
5
6
7
8
9
10
11
{{if .IsAttachment}}
    -- attachment presentation code --
{{end}}

{{if .IsMenu}}
    -- menu --
{{end}}

{{if .IsDefault}}
    -- default code --
{{end}}
  • 除了添加isSomeValue函数,没有其他方法可以测试Type吗?
  • @dystroy很好,重点是将逻辑移出模板。所以,是的,您应该具有辅助功能。每当您使用无逻辑模板时,您就必须在其他技术中执行相同的操作。
  • 实际上,问题始于IsDefault的定义。最后,从复制必须在模板和Go代码中都必须存在的所有表示逻辑开始,最后在Go中以冗长的冗长代码来支持模板,并且模板没有带来任何附加价值。
  • 这太严格了吗?...需要针对字符串求值的条件是什么? @FlorianMargaine
  • 替换:"文本/模板不应该具有这种逻辑。"带有:"文本/模板不支持更复杂的逻辑。"
  • elseelse if
  • 文本/模板包为复杂的逻辑提供了辅助功能。如果{{else if .IsMenu}}不够用,您可以执行类似{{if and .IsMenu (not .IsAttachment)}}的操作。

是的,您可以使用{{else if .IsMenu}}

  • 这可行。 也许这是模板的新功能。 谢谢

您可以通过将自定义功能添加到template.FuncMap中来实现switch功能。

在下面的示例中,我定义了一个函数printPara (paratype int) string,该函数采用您定义的段落类型之一,并相应地更改其输出。

请注意,在实际模板中,将.Paratype传递给printpara函数。这是在模板中传递参数的方法。请注意,添加到FuncMap的函数的输出参数的数量和形式受到限制。此页面包含一些良好的信息以及第一个链接。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package main

import (
   "fmt"
   "os"
   "html/template"
)

func main() {

    const (
        paragraph_hypothesis = 1 << iota
        paragraph_attachment = 1 << iota
        paragraph_menu       = 1 << iota
    )

    const text ="{{.Paratype | printpara}}\
" // A simple test template

    type Paragraph struct {
        Paratype int
    }

    var paralist = []*Paragraph{
        &Paragraph{paragraph_hypothesis},
        &Paragraph{paragraph_attachment},
        &Paragraph{paragraph_menu},
    }

    t := template.New("testparagraphs")

    printPara := func(paratype int) string {
        text :=""
        switch paratype {
        case paragraph_hypothesis:
            text ="This is a hypothesis\
"
        case paragraph_attachment:
            text ="This is an attachment\
"
        case paragraph_menu:
            text ="Menu\
1:\
2:\
3:\
\
Pick any option:\
"
        }
        return text
    }

    template.Must(t.Funcs(template.FuncMap{"printpara": printPara}).Parse(text))

    for _, p := range paralist {
        err := t.Execute(os.Stdout, p)
        if err != nil {
            fmt.Println("executing template:", err)
        }
    }
}

产生:

This is a hypothesis

This is an attachment

Menu
1:
2:
3:

Pick any option:

游乐场链接

希望能有所帮助,我很确定可以对代码进行一些整理,但我尝试与您提供的示例代码保持紧密联系。

  • 这很有趣,但是在您的解决方案中,HTML段落的呈现是在Go(在printPara中)完成的。然后,使用模板似乎没有任何意义。
  • 印刷仅是示范。您可以在case语句中插入任何代码,而不仅仅是自定义输出。您可以处理变量,更改结构值等。这实际上只是为了演示如何在模板中生成类似switch的功能。
  • @Intermernet,但是您在那里没有在模板中生成任何switch之类的功能。我想我也想有一个更好的例子。
  • 抱歉,我仍然不确定您要实现的目标,golang.org/pkg/text/template具有go native模板的所有功能。除了那里列出的内置功能之外,向FuncMap添加功能是我知道的修改输出的唯一方法。 @FlorianMargaine,该函数接受单个整数(菜单可能类似于菜单的{{4 | printpara}}),并且在内部通过对该整数执行switch语句来更改其行为。就像我可以在模板中模拟的那样,那与本地golang switch差不多。
  • @Intermernet我认为自己和我都在寻找这样的东西:pastebin.com/QSz0vAxk
  • 那正是我一直在寻找的东西。
  • @FlorianMargaine和@dystroy,驱动模板的数据是否来自结构?可能是类似type Paragraph struct{Paratype int, Text string}的东西吗?
  • @Intermernet是的,我删除了该结构的其他字段以使其更简单(并且在我当时那明显的错误观点中,使它更清楚)。
  • @dystroy,好吧,我想我可以重构该函数以使其接近您想要的功能。这是一个有趣的挑战,Ive甚至正在阅读源代码,以尝试确定if语句在模板中的工作方式。尽管notandor如此,但if并不是内置模板功能之一。希望我很快就会有事情:-)
  • 好的,经过大量阅读之后,似乎Id需要修改标准库(特别是对于初学者来说,尤其是golang.org/pkg/text/template/parse/#NodeType)才能实现真正的switch语句。 接下来最好的事情是一系列{{if switch .Type | case 1}}...{{end}}(在FuncMap中定义自定义的Switch()Case()函数),此时,您也可以只使用标准的if语句。 嗯,最近一小时左右,我就对词法分析器和解析器学到了很多东西! 如果您感兴趣的话,相关的资源在golang.org/src/pkg/text/template/parse。