Golang模板中可以使用ENUM吗?

Golang模板中可以使用ENUM吗? 在我的代码中,我定义了一个枚举如下:

type flag int

const (
	Admin flag = iota + 1 // iota = 0
	Editer
	Superuser
	Viewer
)

该信息被传递到模板中,我进行如下比较:

        {{range $i, $v := .Flags}}
                {{if or (eq $v 1) (eq $v 3)}} 
                    <input type="text" name="subject" placeholder= {{$v}} required>
                {{else}}
                        <input type="text" name="subject" placeholder= {{$v}} disabled>
                {{end}}

        {{end}}

如这里所见,比较是使用等效的整数值 eq $v 1 完成的,我希望做的是类似 eq $v Admin 这样,以便使用枚举名称而不是其值。

我可以这样做吗?


更多关于Golang模板中可以使用ENUM吗?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

我找到了解决方案,使用了方法值,具体实现如这里所示。

package main

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

type flag int

func (f flag) get() flag { return f }

const (
	Admin flag = iota + 1 // iota = 0
	Editor
)

var funcMap = template.FuncMap{
	"Admin":  Admin.get,
	"Editor": Editor.get,
	// ...
}

var file = `{{ $v := . }}
{{- if eq $v Admin }}is admin{{ else }}is not admin{{ end }}
{{ if eq $v Editor }}is editor{{ else }}is not editor{{ end }}
`

func main() {
	t := template.Must(template.New("t").Funcs(funcMap).Parse(file))

	if err := t.Execute(os.Stdout, Admin); err != nil {
		panic(err)
	}
	fmt.Println("----------------")
	if err := t.Execute(os.Stdout, Editor); err != nil {
		panic(err)
	}
	fmt.Println("----------------")
	if err := t.Execute(os.Stdout, 1234); err != nil {
		panic(err)
	}
	fmt.Println("----------------")
}

更多关于Golang模板中可以使用ENUM吗?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go模板中直接使用枚举常量名(如Admin)是不可行的,因为模板引擎无法直接访问Go代码中的常量定义。不过,你可以通过以下几种方式实现类似的效果:

方法1:在模板中定义映射

在传递给模板的数据结构中添加一个映射,将枚举值转换为可读的字符串:

type TemplateData struct {
    Flags []flag
    FlagNames map[flag]string
}

// 在渲染模板前初始化映射
data := TemplateData{
    Flags: []flag{Admin, Editer, Superuser, Viewer},
    FlagNames: map[flag]string{
        Admin:     "Admin",
        Editer:    "Editer", 
        Superuser: "Superuser",
        Viewer:    "Viewer",
    },
}

然后在模板中使用:

{{range $i, $v := .Flags}}
    {{if or (eq $v 1) (eq $v 3)}}
        <input type="text" name="subject" placeholder="{{index $.FlagNames $v}}" required>
    {{else}}
        <input type="text" name="subject" placeholder="{{index $.FlagNames $v}}" disabled>
    {{end}}
{{end}}

方法2:为枚举类型实现String()方法

为你的枚举类型实现String()方法,这样在模板中可以直接调用:

type flag int

const (
    Admin flag = iota + 1
    Editer
    Superuser
    Viewer
)

func (f flag) String() string {
    switch f {
    case Admin:
        return "Admin"
    case Editer:
        return "Editer"
    case Superuser:
        return "Superuser"
    case Viewer:
        return "Viewer"
    default:
        return "Unknown"
    }
}

在模板中直接使用:

{{range $i, $v := .Flags}}
    {{if or (eq $v 1) (eq $v 3)}}
        <input type="text" name="subject" placeholder="{{$v.String}}" required>
    {{else}}
        <input type="text" name="subject" placeholder="{{$v.String}}" disabled>
    {{end}}
{{end}}

方法3:使用模板函数

注册自定义模板函数来处理枚举比较:

func main() {
    funcMap := template.FuncMap{
        "isAdmin": func(f flag) bool { return f == Admin },
        "isSuperuser": func(f flag) bool { return f == Superuser },
    }
    
    tmpl := template.Must(template.New("").Funcs(funcMap).Parse(templateStr))
}

在模板中使用:

{{range $i, $v := .Flags}}
    {{if or (isAdmin $v) (isSuperuser $v)}}
        <input type="text" name="subject" placeholder="{{$v.String}}" required>
    {{else}}
        <input type="text" name="subject" placeholder="{{$v.String}}" disabled>
    {{end}}
{{end}}

方法4:使用常量映射(推荐)

创建一个包级别的映射,用于在模板中查找:

var FlagNames = map[flag]string{
    Admin:     "Admin",
    Editer:    "Editer",
    Superuser: "Superuser",
    Viewer:    "Viewer",
}

// 在模板数据中包含这个映射
data := struct {
    Flags []flag
    FlagNames map[flag]string
}{
    Flags: flags,
    FlagNames: FlagNames,
}

这些方法都能让你在模板中避免直接使用硬编码的整数值,提高代码的可读性和可维护性。

回到顶部