表达式系统 ========== 概述 ---- 从上面的动态sql里面我们可以看出 juice 支持在 ``if`` 和 ``when`` 标签中使用表达式,这些表达式的语法和 go 语言中的语法基本一致。 使用限制 -------- 1. juice 只支持单行表达式,不支持多行表达式。 2. 当在表达式里面写一个字符串的时候,需要将test属性的的值用单引号包裹起来,例如: .. code:: xml 3. 尽量写简单一点的表达式。 基本运算符 ---------- 比较运算符 ~~~~~~~~~~ juice 支持以下比较运算符: 1. ``==``: 判断两个值是否相等。 2. ``!=``: 判断两个值是否不相等。 3. ``>``: 判断左边的值是否大于右边的值。 4. ``>=``: 判断左边的值是否大于等于右边的值。 .. attention:: ``<`` 和 ``<=`` 不支持,因为它们会跟xml的语法冲突。那么怎么办呢?我们可以使用 ``<`` 和 ``<=`` 来代替 ``<`` 和 ``<=``。 逻辑运算符 ~~~~~~~~~~ juice 支持以下逻辑运算符: 1. ``and``: 逻辑与。 2. ``or``: 逻辑或。 3. ``!``: 逻辑非。 算术运算符 ~~~~~~~~~~ juice 支持以下算术运算符: 1. ``+``: 加法运算。 2. ``-``: 减法运算。 3. ``*``: 乘法运算。 4. ``/``: 除法运算。 5. ``%``: 取余运算。 保留关键字 ~~~~~~~~~~ 保留关键字是指 juice 里面已经定义好的关键字,不能用作变量名: 1. ``true``: 布尔类型的真。 2. ``false``: 布尔类型的假。 3. ``nil``: 空值。 4. ``and``: 逻辑与。 5. ``or``: 逻辑或。 内置函数 -------- juice 内置了一些常用函数。这些函数由 ``github.com/go-juicedev/juice/eval`` 包注册,可直接在动态 SQL 表达式中使用。 1. ``len``: 返回字符串、数组、切片、map 或 channel 的长度。 .. code-block:: go func len(any) (int, error) 2. ``substr``: 返回字符串的子串。 .. code-block:: go func substr(string, int, int) (string, error) 3. ``join``: 将字符串数组或切片用分隔符连接。 .. code-block:: go func join(any, string) (string, error) 4. ``slice``: 对数组或切片进行切片操作。 .. code-block:: go func slice(any, int, int) ([]any, error) 5. ``lower``: 转换为小写。 .. code-block:: go func lower(string) (string, error) 6. ``upper``: 转换为大写。 .. code-block:: go func upper(string) (string, error) 7. ``trim``、``trimLeft``、``trimRight``: 去除字符串两端或指定方向的字符。 .. code-block:: go func trim(string, string) (string, error) 8. ``replace`` 和 ``replaceAll``: 替换字符串中的子串。 .. code-block:: go func replace(string, string, string, int) (string, error) func replaceAll(string, string, string) (string, error) 9. ``split``、``splitN``、``splitAfter``: 分割字符串。 .. code-block:: go func split(string, string) ([]string, error) func splitN(string, string, int) ([]string, error) func splitAfter(string, string) ([]string, error) 自定义函数 ---------- 注册条件: 1. 必须是一个函数 2. 必须有两个返回值,第一个返回值是任意类型,第二个必须为error类型 示例代码: .. code:: go func add(x, y int) (int, error) { return x + y, nil } func main() { if err := eval.RegisterEvalFunc("add", add); err != nil { panic(err) } } 注册自定义函数时,需要显式导入 ``eval`` 包: .. code-block:: go import "github.com/go-juicedev/juice/eval" 使用示例: .. code:: xml 函数调用 -------- 基本函数调用: .. code-block:: xml .. code-block:: go func MyFunc() (string, error) { return "eatmoreapple", nil } param := juice.H{ "MyFunc": MyFunc, } 带参数函数: .. code-block:: xml .. code-block:: go func MyFunc(str string) (string, error) { return str, nil } param := juice.H{ "MyFunc": MyFunc, } 参数引用: .. code-block:: xml .. code-block:: go param := juice.H{ "MyFunc": MyFunc, "eatmoreapple": "eatmoreapple", } 多参数函数: .. code-block:: xml .. code-block:: go func MyFunc(str string, x, y int) (string, error) { return str, nil } 自定义类型方法 -------------- 方法调用: .. code-block:: xml .. code-block:: go type A struct { Name string } func (a *A) MyFunc() (string, error) { return a.Name, nil } param := juice.H{ "a": &A{Name: "eatmoreapple"}, } 属性访问 -------- 结构体属性: .. code-block:: xml .. code-block:: go type A struct { Name string } param := juice.H{ "a": &A{Name: "eatmoreapple"}, } Map操作 ------- 索引访问: .. code-block:: go param := juice.H{ "a": juice.H{ "Name": "eatmoreapple", }, } .. code-block:: xml .. attention:: 区别: 1. 索引访问(``a["Name"]``)在key不存在时返回默认值 2. 点号访问(``a.Name``)在属性不存在时抛出异常 3. 点号访问支持方法调用 数组操作 -------- .. code-block:: xml .. code-block:: go param := juice.H{ "a": []string{"eatmoreapple"}, } 也支持切片表达式: .. code-block:: xml 下标和切片边界必须计算为整数类型。单个负数下标会从数组或切片末尾开始计数,例如 ``a[-1]`` 返回最后一个元素。 .. tip:: 最佳实践: 1. 保持表达式简单明了 2. 复杂逻辑建议在Go代码中处理 3. 合理使用内置函数 4. 注意XML特殊字符转义 5. 测试所有条件分支