Go 表達式引擎之理解與使用 cel-go
在現代應用中,表達式求值引擎已經成爲許多系統不可或缺的一部分。它可以讓業務邏輯與代碼分離,爲動態規則配置提供極大的靈活性。而 Google 開源的 cel-go (Common Expression Language for Go) 就是這樣一款輕量級、高性能的表達式求值引擎。無論你是初學者還是需要在項目中集成 cel-go,這篇文章都將帶你從入門到精通!
什麼是 CEL 和 cel-go?
CEL(Common Expression Language) 是一種輕量級的表達式語言,專注於安全性和嵌入式執行。它最早被設計用來簡化 Google 內部配置系統的表達式處理,後來逐漸開源。
cel-go 是 Google 提供的 Go 語言實現,常用於動態策略管理、數據過濾、權限控制等場景。
爲什麼選擇 cel-go?
輕量高效:cel-go 執行表達式非常快,適合高性能需求的場景。
靈活擴展:支持自定義函數和變量,滿足複雜業務邏輯需求。
安全沙盒:表達式在隔離的環境中執行,不會直接操作主程序的數據,避免安全風險。
豐富的類型支持:內置支持常見的數據類型(如數字、字符串、布爾值、列表、映射等)。
cel-go 的核心概念
在學習 cel-go 之前,我們需要理解幾個重要概念:
1. 環境(Environment):執行表達式的上下文,定義了可以使用的變量和函數。
2. 表達式(Expression):用戶輸入的邏輯語句,比如 age > 18 或 name == "Alice"。
3. 編譯(Compile):將表達式解析、檢查並生成可執行程序。
4. 求值(Evaluate):執行編譯後的表達式,並根據傳入的變量值計算結果。
入門示例:Hello, cel-go!
以下是一個簡單示例:檢查一個用戶的年齡是否大於 18 歲。
package main
import (
"fmt"
"log"
"github.com/google/cel-go/cel"
)
func main() {
// 創建環境,定義變量
env, err := cel.NewEnv(
cel.Variable("age", cel.IntType), // 定義變量age
)
if err != nil {
log.Fatalf("created environment failed: %v", err)
}
expr := "age >= 18" // 定義表達式
ast, iss := env.Compile(expr) // 解析並檢查表達式
if iss.Err() != nil { // 檢測表達式是否錯誤
log.Fatalf("compilation failed: %v", err)
}
pro, err := env.Program(ast) // 編譯並執行表達式
if err != nil {
log.Fatalf("program creation failed: %v", err)
}
out, _, err := pro.Eval(map[string]any{
// 將age設置爲18,並將其傳入到表達式中
"age": 18,
})
if err != nil {
log.Fatalf("evaluation failed: %v", err)
}
fmt.Println(out) // 輸出結果爲true
}
自定義函數
在實際項目中,我們可能需要定義自己的函數。以下示例實現了一個簡單的函數 double,用於將輸入數字乘以 2。
package main
import (
"fmt"
"log"
"github.com/google/cel-go/cel"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
)
func main() {
env, err := cel.NewEnv(
cel.Function("my_double", // 定義函數,並起名爲my_double
cel.Overload("my_double_int", // 實現函數,my_double_int是函數的唯一標識
[]*cel.Type{cel.IntType}, // 定義函數入參的類型
cel.IntType, // 定義函數返回值類型
cel.UnaryBinding( // 函數體具體實現
func(value ref.Val) ref.Val {
if intVal, ok := value.(types.Int); ok {
return types.Int(intVal * 2)
}
return types.NewErr("invalid argument type")
},
),
),
),
)
if err != nil {
log.Fatalf("created environment failed: %v", err)
}
expr := `my_double(5) == 10` // 調用my_double函數並將其結果和10進行相等比較
ast, iss := env.Compile(expr) // 解析並檢查表達式是否正確
if iss.Err() != nil {
log.Fatalf("compilation failed: %v", iss.Err())
}
program, err := env.Program(ast) // 執行表達式
if err != nil {
log.Fatalf("program creation failed: %v", err)
}
out, _, err := program.Eval(map[string]any{})
// my_double函數我們直接傳入5,所以這裏傳遞參數時爲空即可
if err != nil {
log.Fatalf("evaluation failed: %v", err)
}
fmt.Println(out) // 輸出結果爲true
}
Cel-go 典型應用場景
1. 動態權限控制:例如,定義用戶權限規則 role == "admin" && department == "IT"。
2. 業務規則引擎:根據配置的表達式動態調整業務邏輯。
3. 數據過濾:如基於條件過濾日誌或數據庫記錄。
- 漏洞檢測插件: 通過編寫漏洞檢測規則來檢測漏洞。
總結
cel-go 是一個功能強大、靈活的工具,能夠幫助開發者快速構建動態邏輯求值系統。從基本變量的定義到高級自定義函數的實現,cel-go 提供了豐富的擴展能力。希望本文能幫助你快速上手,並將它靈活地運用到實際項目中!
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/9dna2g6Mmz0Bn7_aKoZHKQ