golang代码生成工具提供泛型、自由格式宏、条件编译和HTML模板插件generis的使用

Generis - Golang 代码生成工具

Generis Logo

Generis 是一个轻量级的代码预处理器,为 Go 语言添加了以下特性:

  • 泛型
  • 自由格式宏
  • 条件编译
  • HTML 模板
  • Allman 风格转换

示例代码

以下是一个完整的示例,展示了 Generis 的主要功能:

package main;

// -- IMPORTS

import (
    "html"
    "io"
    "log"
    "net/http"
    "net/url"
    "strconv"
    );

// -- DEFINITIONS

#define DebugMode
#as true

// ~~

#define HttpPort
#as 8080

// ~~

#define WriteLine( {{text}} )
#as log.Println( {{text}} )

// ~~

#define local {{variable}} : {{type}};
#as var {{variable}} {{type}};

// ~~

#define DeclareStack( {{type}}, {{name}} )
#as
    // -- TYPES

    type {{name}}Stack struct
    {
        ElementArray []{{type}};
    }

    // -- INQUIRIES

    func ( stack * {{name}}Stack ) IsEmpty(
        ) bool
    {
        return len( stack.ElementArray ) == 0;
    }

    // -- OPERATIONS

    func ( stack * {{name}}Stack ) Push(
        element {{type}}
        )
    {
        stack.ElementArray = append( stack.ElementArray, element );
    }

    // ~~

    func ( stack * {{name}}Stack ) Pop(
        ) {{type}}
    {
        local
            element : {{type}};

        element = stack.ElementArray[ len( stack.ElementArray ) - 1 ];

        stack.ElementArray = stack.ElementArray[ : len( stack.ElementArray ) - 1 ];

        return element;
    }
#end

// ~~

#define DeclareStack( {{type}} )
#as DeclareStack( {{type}}, {{type:PascalCase}} )

// -- TYPES

DeclareStack( string )
DeclareStack( int32 )

// -- FUNCTIONS

func HandleRootPage(
    response_writer http.ResponseWriter,
    request * http.Request
    )
{
    local
        boolean : bool;
    local
        natural : uint;
    local
        integer : int;
    local
        real : float64;
    local
        escaped_html_text,
        escaped_url_text,
        text : string;
    local
        integer_stack : Int32Stack;

    boolean = true;
    natural = 10;
    integer = 20;
    real = 30.0;
    text = "text";
    escaped_url_text = "&escaped text?";
    escaped_html_text = "<escaped text/>";

    integer_stack.Push( 10 );
    integer_stack.Push( 20 );
    integer_stack.Push( 30 );

    #write response_writer
        <!DOCTYPE html>
        <html lang="en">
            <head>
                <meta charset="utf-8">
                <title><%= request.URL.Path %></title>
            </head>
            <body>
                <% if ( boolean ) { %>
                    <%= "URL : " + request.URL.Path %>
                    <br/>
                    <%@ natural %>
                    <%# integer %>
                    <%&amp; real %>
                    <br/>
                    <%~ text %>
                    <%^ escaped_url_text %>
                    <%= escaped_html_text %>
                    <%= "<%% ignored %%>" %>
                    <%% ignored %%>
                <% } %>
                <br/>
                Stack :
                <br/>
                <% for !integer_stack.IsEmpty() { %>
                    <%# integer_stack.Pop() %>
                <% } %>
            </body>
        </html>
    #end
}

// ~~

func main()
{
    http.HandleFunc( "/", HandleRootPage );

    #if DebugMode
        WriteLine( "Listening on http://localhost:HttpPort" );
    #end

    log.Fatal(
        http.ListenAndServe( ":HttpPort", nil )
        );
}

语法说明

#define 指令

常量和通用代码可以使用以下语法定义:

#define old code
#as new code

#define old code
#as
    new
    code
#end

#define
    old
    code
#as new code

#define
    old
    code
#as
    new
    code
#end

#if 指令

条件代码可以使用以下语法定义:

#if boolean expression
    #if boolean expression
        ...
    #else
        ...
    #end
#else
    #if boolean expression
        ...
    #else
        ...
    #end
#end

#write 指令

模板化的 HTML 代码可以使用以下语法发送到流写入器:

#write writer expression
    <% code %>
    <%@ natural expression %>
    <%# integer expression %>
    <%&amp; real expression %>
    <%~ text expression %>
    <%= escaped text expression %>
    <%! removed content %>
    <%% ignored tags %%>
#end

安装

  1. 安装 DMD 2 编译器(在 Windows 上使用 MinGW 设置选项)
  2. 使用以下命令构建可执行文件:
dmd -m64 generis.d

使用示例

generis --process GS/ GO/

读取 GS/ 文件夹中的 Generis 文件并将 Go 文件写入 GO/ 文件夹。

generis --process GS/ GO/ --create --watch

读取 GS/ 文件夹中的 Generis 文件并将 Go 文件写入 GO/ 文件夹,如果需要则创建输出文件夹,并监视 Generis 文件的修改。

版本

2.0

作者

Eric Pelzer (ecstatic.coder@gmail.com)

许可证

本项目根据 GNU 通用公共许可证第 3 版授权。


更多关于golang代码生成工具提供泛型、自由格式宏、条件编译和HTML模板插件generis的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang代码生成工具提供泛型、自由格式宏、条件编译和HTML模板插件generis的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang 代码生成工具 Generis 使用指南

Generis 是一个强大的 Go 代码生成工具,提供了泛型、自由格式宏、条件编译和 HTML 模板插件等功能。下面我将详细介绍如何使用 Generis 的这些特性。

1. 安装 Generis

首先需要安装 Generis 工具:

go get github.com/jojomi/generis

2. 泛型支持

Generis 通过代码生成实现了类似泛型的功能。下面是一个泛型容器的示例:

// +generis
// +template Container(T)
package main

type Container[T any] struct {
    items []T
}

func (c *Container[T]) Add(item T) {
    c.items = append(c.items, item)
}

func (c *Container[T]) Get(index int) T {
    return c.items[index]
}

// +endtemplate

然后运行 Generis 生成具体类型的容器:

generis --template Container --type int --output container_int.go
generis --template Container --type string --output container_string.go

3. 自由格式宏

Generis 支持自由格式宏,可以在代码中插入动态内容:

// +generis
// +macro IMPORT_TIME
import "time"
// +endmacro

// +macro LOG_FUNC
func log(msg string) {
    fmt.Println(time.Now().Format("2006-01-02 15:04:05"), msg)
}
// +endmacro

package main

// +IMPORT_TIME

func main() {
    // +LOG_FUNC
    log("Hello, Generis!")
}

4. 条件编译

Generis 支持条件编译,可以根据不同条件生成不同的代码:

// +generis
// +ifdef DEBUG
const debug = true
// +else
const debug = false
// +endif

package main

func main() {
    if debug {
        println("Debug mode enabled")
    }
}

生成发布版本代码:

generis --define DEBUG=false --output release.go

5. HTML 模板插件

Generis 可以与 Go 的 HTML 模板结合使用,自动生成类型安全的模板代码:

<!-- user.tmpl.html -->
<!-- +generis -->
{{define "UserCard"}}
<div class="user-card">
    <h2>{{.Name}}</h2>
    <p>Email: {{.Email}}</p>
    <p>Age: {{.Age}}</p>
</div>
{{end}}
<!-- +endgeneris -->

然后生成对应的 Go 代码:

generis --html-template user.tmpl.html --type User --output user_templates.go

生成的代码会包含类型检查的模板调用方法:

func RenderUserCard(u *User) (string, error) {
    // 自动生成的模板渲染代码
}

6. 综合示例

下面是一个综合使用 Generis 特性的示例:

// +generis
// +template Cache(K,V)
package main

import (
    "sync"
    "time"
)

// +ifdef METRICS
var cacheHits int
var cacheMisses int
// +endif

type Cache[K comparable, V any] struct {
    data map[K]V
    mu   sync.RWMutex
    ttl  time.Duration
}

func NewCache[K comparable, V any](ttl time.Duration) *Cache[K, V] {
    return &Cache[K, V]{
        data: make(map[K]V),
        ttl:  ttl,
    }
}

func (c *Cache[K, V]) Get(key K) (V, bool) {
    c.mu.RLock()
    defer c.mu.RUnlock()
    
    val, ok := c.data[key]
    // +ifdef METRICS
    if ok {
        cacheHits++
    } else {
        cacheMisses++
    }
    // +endif
    return val, ok
}

// +endtemplate

生成带监控的字符串缓存:

generis --template Cache --key string --value string --define METRICS=true --output string_cache.go

Generis 的这些特性可以显著提高 Go 开发效率,特别是在需要重复样板代码或类型安全模板的场景下。通过合理使用代码生成,可以在保持 Go 简单性的同时获得类似泛型等高级语言特性的便利。

回到顶部