Go语言DSL:如何为实际任务创建领域特定语言

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Go语言DSL:将您的代码转变为新语言



想象一下,您正在编写一个订单处理系统。每天经理们都会要求:“为所有来自莫斯科的客户添加10%的折扣,但仅当订单金额超过5000时。”您深入代码,修改if-else语句,测试,部署。一周后,新的请求来了:“VIP客户购买超过三件商品时,享受15%的折扣。”熟悉吗?



如果经理们自己就能编写这些规则呢?无需您的参与。没有破坏生产环境的风险。这正是领域特定语言(DSL)存在的意义——针对特定任务量身定制的紧凑语言。而Go,凭借其简洁性和高性能,非常适合创建此类DSL。



在本文中,我们将探讨如何在Go中创建DSL——从简单的可嵌入解决方案到完整的外部解析器。您将学习如何自动化日常任务,并为用户提供一个无需编程就能理解的工具。



什么是DSL,为什么在Go中需要它?



DSL(领域特定语言)是一种为狭窄领域创建的编程语言。与通用语言(Go、Python、Java)不同,DSL解决单一任务,但做得非常优雅。



现实生活中的例子:

  • SQL — 用于数据库操作的DSL。
  • 正则表达式 — 用于文本模式搜索的DSL。
  • HTML — 用于网页标记的DSL。


在Go中,DSL用于:

  • 配置 — 可以用自己的语言编写逻辑,替代YAML/JSON。
  • 业务规则 — 让分析师无需程序员即可更改逻辑。
  • 测试 — 以可读形式描述场景。
  • 数据处理 — 创建转换管道。


选择Go并非偶然:其编译器速度快,语法简洁,内置工具(例如text/scanner或go/ast)简化了解析。但最重要的是,Go允许创建内部DSL(嵌入到Go语法中)和外部DSL(具有自己的语法和解析器)。



Go中的内部DSL:利用语言语法



内部DSL是看起来像独立语言但使用Go语法的库。它们不需要编写解析器:您只需编写可以“链接”成调用链的函数。



示例:折扣规则DSL



假设我们希望规则看起来像这样:



discount := Rule("VIP折扣").    When(City("莫斯科")).    When(OrderSum > 5000).    Apply(Discount(10))


如何在Go中实现?使用Builder模式和高级函数:



package main

import "fmt"

// Rule - 规则结构type Rule struct { Name string Checks []func(order map[string]interface{}) bool Discount int}

// When 添加条件func (r *Rule) When(check func(order map[string]interface{}) bool) *Rule { r.Checks = append(r.Checks, check) return r}

// Apply 设置折扣func (r *Rule) Apply(discount int) *Rule { r.Discount = discount return r}

// Evaluate 检查订单是否符合条件func (r *Rule) Evaluate(order map[string]interface{}) bool { for _, check := range r.Checks { if !check(order) { return false } } return true}

// 辅助条件函数func City(city string) func(map[string]interface{}) bool { return func(order map[string]interface{}) bool { return order["city"] == city }}

func OrderSum(order map[string]interface{}) int { return order["sum"].(int)}

// 通过闭包重载 > 运算符func GreaterThan(a func(map[string]interface{}) int, b

博客

书籍推荐