golang增强Go模板功能的实用插件库sprout的使用

Golang增强Go模板功能的实用插件库Sprout的使用

Sprout Logo

简介

Sprout是Masterminds/sprig库的现代化演进版本,专为现代Go版本重新设计。它引入了新功能并承诺持续维护,填补了Sprig停止更新后的空白。Sprig已有两年未更新且不支持Go 1.13以上版本,因此Sprout应运而生。

动机

Sprout诞生于对现代化、可维护且高性能模板函数库的需求。Sprig作为Sprout的前身,已有两年未更新且未针对较新Go版本优化。Sprout旨在填补这一空白,提供一个积极维护、兼容最新Go版本并优化性能的库。

从Sprig迁移

Sprout提供了sprigin包作为Sprig的临时替代方案,具有相同的函数名称和行为。要使用Sprout,只需将Sprig导入替换为sprigin:

import (
-  "github.com/Masterminds/sprig/v3"
+  "github.com/go-sprout/sprout/sprigin"
)

tpl := template.Must(
  template.New("base").
-   Funcs(sprig.FuncMap()).
+   Funcs(sprigin.FuncMap()).
    ParseGlob("*.tmpl")
)

重要提示sprigin包是提供与Sprig向后兼容的临时解决方案。我们建议更新代码以直接使用Sprout包,以利用新功能和改进。

使用指南

创建处理器

Sprout中的处理器负责管理函数注册表和函数。DefaultHandler是Sprout提供的主要实现。

import "github.com/go-sprout/sprout"

handler := sprout.New()

自定义处理器

Sprout支持使用处理器选项进行各种自定义:

handler := sprout.New(
  // 添加日志记录器到处理器,使用标准slog包或任何实现slog.Logger接口的日志记录器
  // 默认情况下,Sprout使用slog.TextHandler
  sprout.WithLogger(slogLogger),
  // 为函数设置别名。默认情况下,Sprout为某些函数使用别名以保持与Sprig的兼容性
  sprout.WithAlias("hello", "hi"),
)

使用注册表

Sprout中的注册表是可以添加到处理器的函数组。它们有助于组织函数并优化模板性能。

import (
  "github.com/go-sprout/sprout/registry/conversion" // toString, toInt, toBool, ...
  "github.com/go-sprout/sprout/registry/std" // default, empty, any, all, ...
)

//...

handler.AddRegistries(
  conversion.NewRegistry(),
  std.NewRegistry(),
)

使用注册表组

在某些情况下,可以使用注册表组一次性添加多个注册表。

import (
  "github.com/go-sprout/sprout/group/all"
)

//...

handler.AddGroup(
  all.RegistryGroup(),
)

构建函数映射

要与html/templatetext/template等模板引擎一起使用Sprout,需要构建函数映射:

funcs := handler.Build()
tpl := template.New("example").Funcs(funcs).Parse(`{{ hello }}`)

使用模板

函数映射准备好后,可以使用它来渲染模板:

tpl, err := template.New("example").Funcs(funcs).Parse(`{{ myFunc }}`)
if err != nil {
    log.Fatal(err)
}
tpl.Execute(os.Stdout, nil)

快速示例

以下是如何与text/template包一起使用Sprout的快速示例:

package main

import (
	"os"
	"text/template"

	"github.com/go-sprout/sprout"
	"github.com/go-sprout/sprout/registry/std"
)

func main() {
	handler := sprout.New()
	handler.AddRegistry(std.NewRegistry())

	tpl := template.Must(
    template.New("example").Funcs(handler.Build()).Parse(`{{ hello }}`),
  )
	tpl.Execute(os.Stdout, nil)
}

性能基准

Sprig v3.2.3 vs Sprout v0.5

goos: linux
goarch: amd64
pkg: sprout_benchmarks
cpu: Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz
BenchmarkSprig-16              1        2991811373 ns/op        50522680 B/op      32649 allocs/op
BenchmarkSprout-16             1        1638797544 ns/op        42171152 B/op      18061 allocs/op
PASS
ok      sprout_benchmarks       4.921s

时间改进:45.3%
内存改进:16.5%

因此,Sprout v0.5比Sprig v3.2.3快约45.3%,内存使用减少16.5%。

开发理念

我们扩展和完善Sprout的方法遵循以下几个关键原则:

  • 建立在简单性、灵活性和一致性的原则上
  • 使开发人员能够创建强大的模板,而不牺牲性能或可用性
  • 严格遵守Go的模板约定,确保熟悉Go原生工具的开发人员获得无缝体验
  • 跨函数的命名约定标准化以实现可预测性和易用性
  • 强调错误处理,倾向于安全默认值而非panic
  • 提供清晰全面的文档以帮助用户理解库及其功能
  • 保持高水平的代码质量,确保库经过良好测试、高性能且可靠
  • 持续改进和优化库以满足社区需求
  • 避免模板函数中的任何外部依赖,确保所有操作都是自包含且可靠的
  • 性能是关键考虑因素,重点优化库的速度和效率

更多关于golang增强Go模板功能的实用插件库sprout的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang增强Go模板功能的实用插件库sprout的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Sprout - 增强Go模板功能的实用插件库

Sprout 是一个为 Go 模板引擎 (html/template 和 text/template) 提供增强功能的库,它添加了许多有用的模板函数,使模板开发更加便捷。下面我将介绍 Sprout 的主要功能和使用方法。

安装

go get github.com/gobuffalo/sprout

基本使用

package main

import (
	"html/template"
	"os"
	
	"github.com/gobuffalo/sprout"
)

func main() {
	// 创建模板函数映射
	funcMap := sprout.FuncMap()
	
	// 创建模板并添加函数
	tmpl := template.New("example").Funcs(funcMap)
	
	// 解析模板内容
	tmpl, err := tmpl.Parse(`
{{/* 使用Sprout提供的函数 */}}
{{ json .Data | pretty }}
{{ date "2006-01-02" .Timestamp }}
{{ truncate 10 "This is a long string" }}
`)
	if err != nil {
		panic(err)
	}
	
	// 执行模板
	data := map[string]interface{}{
		"Data": map[string]string{
			"name": "John",
			"age":  "30",
		},
		"Timestamp": "2023-05-15T12:00:00Z",
	}
	
	err = tmpl.Execute(os.Stdout, data)
	if err != nil {
		panic(err)
	}
}

常用功能分类

1. 字符串处理

// 模板示例
{{ "hello" | upper }} // 输出: HELLO
{{ "WORLD" | lower }} // 输出: world
{{ "foo bar baz" | title }} // 输出: Foo Bar Baz
{{ "This is too long" | truncate 10 }} // 输出: This is...
{{ "Hello $name" | replace "$name" "John" }} // 输出: Hello John
{{ "a,b,c" | split "," }} // 输出: [a b c] (切片)

2. 日期时间处理

// 模板示例
{{ now }} // 当前时间
{{ date "2006-01-02" .someTime }} // 格式化时间
{{ dateInZone "2006-01-02 15:04:05" .someTime "UTC" }} // 指定时区格式化
{{ .someTime | ago }} // 相对时间,如"2 hours ago"

3. 数学运算

// 模板示例
{{ add 1 2 }} // 3
{{ sub 5 3 }} // 2
{{ mul 2 3 }} // 6
{{ div 6 3 }} // 2
{{ mod 5 2 }} // 1
{{ min 5 2 8 }} // 2
{{ max 5 2 8 }} // 8

4. 集合操作

// 模板示例
{{ $slice := slice "a" "b" "c" }}
{{ $slice | first }} // a
{{ $slice | last }} // c
{{ $slice | join "-" }} // a-b-c
{{ $slice | contains "b" }} // true
{{ $slice | reverse }} // [c b a]

5. JSON处理

// 模板示例
{{ $data := dict "name" "John" "age" 30 }}
{{ $data | json }} // {"name":"John","age":30}
{{ $data | json | pretty }} // 格式化后的JSON
{{ `{"name":"John"}` | fromJSON }} // 解析JSON为map

6. 条件判断增强

// 模板示例
{{ if eq .User.Role "admin" | or (eq .User.Role "editor") }}
  高级用户内容
{{ end }}

{{ default "guest" .User.Name }} // 如果.User.Name为空则使用"guest"

7. 字典操作

// 模板示例
{{ $user := dict "name" "John" "age" 30 }}
{{ $user | get "name" }} // John
{{ set $user "email" "john@example.com" }} // 添加/修改字段
{{ keys $user }} // 获取所有键 [name age email]
{{ values $user }} // 获取所有值 [John 30 john@example.com]

高级用法

自定义函数

你可以将 Sprout 的函数与你自己的自定义函数结合使用:

funcMap := template.FuncMap{
	"greet": func(name string) string {
		return "Hello, " + name + "!"
	},
}

// 合并Sprout的函数
for k, v := range sprout.FuncMap() {
	funcMap[k] = v
}

tmpl := template.New("example").Funcs(funcMap)

性能考虑

Sprout 的函数是即时计算的,对于高性能场景,建议:

  1. 在可能的情况下,在 Go 代码中预处理数据
  2. 避免在循环中使用复杂的 Sprout 函数
  3. 对频繁使用的模板进行缓存

总结

Sprout 为 Go 模板引擎提供了大量实用函数,极大地扩展了模板的功能,使得许多原本需要在 Go 代码中处理的操作可以直接在模板中完成。它特别适合需要复杂模板逻辑的 Web 应用场景。

通过合理使用 Sprout,你可以保持业务逻辑和表现层的良好分离,同时减少模板中的重复代码,提高开发效率。

回到顶部