expr包的使用

expr_basic_test

package expr_practice

import (
    "errors"
    "fmt"
    "github.com/antonmedv/expr"
    "testing"
    "time"
)

// https://github.com/antonmedv/expr
// 优秀文档地址:https://czyt.tech/post/golang-expr-uncompleted-reference/#%e5%9f%ba%e7%a1%80%e4%bd%bf%e7%94%a8

// notice 表达式计算
func TestT1(t *testing.T) {

    env := map[string]interface{}{
        "foo": 1,
        "bar": 2,
    }
    out, err := expr.Eval("foo + bar", env)
    if err != nil {
        panic(err)
    }
    fmt.Print(out) // 3
}

// notice 代码片段编译执行: 内置的函数
func TestT2(t *testing.T) {
    // 普通函数
    envMap := map[string]interface{}{
        "greet":   "Hello, %v!",
        "names":   []string{"world", "you"},
        "Sprintf": fmt.Sprintf, // You can pass any functions.
    }
    // Notice 这个是存到数据库的表达式
    code := `Sprintf(greet, names[0])`
    // Notice Compile code into bytecode. This step can be done once and program may be reused.
    // Specify environment for type check.
    program, err := expr.Compile(code, expr.Env(envMap))
    if err != nil {
        panic(err)
    }
    output, err1 := expr.Run(program, envMap)
    if err1 != nil {
        panic(err1)
    }
    fmt.Println("output: ", output) // output:  Hello, world!
}

// notice 自定义函数
func TestT3(t *testing.T) {
    env := map[string]interface{}{
        "foo":  1,
        "moo":  2,
        "plus": func(i, j int) int { return i + j },
    }
    out, err := expr.Eval("plus(foo, moo)", env)
    if err != nil {
        panic(err)
    }
    fmt.Println(out) // 3
}

// notice 结构体方法/对象方法 对象方法必须是导出的
type Env struct {
    Tweets []Tweet
}
type Tweet struct {
    Text string
    Date time.Time
}

// 结构体方法
func (Env) Format(t time.Time) string {
    return t.Format(time.RFC822)
}
func TestT4(t *testing.T) {

    // 过滤:传入的对象中 Text属性大于5的做一下format~ TODO???返回结果如何取值?
    code := `map(filter(Tweets, {len(.Text) > 5}), {.Text + Format(.Date)})`

    // Notice: We can use an empty instance of the struct as an environment.
    program, err := expr.Compile(code, expr.Env(Env{}))
    if err != nil {
        panic(err)
    }
    envObj := Env{
        Tweets: []Tweet{{"whw", time.Now()}, {"sasuke", time.Now()}, {"naruto", time.Now()}},
    }
    output, err1 := expr.Run(program, envObj)
    if err1 != nil {
        panic(err1)
    }
    fmt.Printf("output: %v, typeOfOutput: %T \n", output, output)
    // output: [sasuke01 Nov 22 11:07 CST naruto01 Nov 22 11:07 CST], typeOfOutput: []interface {}
    fmt.Println(len(output.([]interface{}))) // 2
}

// notice: Fast    functions
// Fast functions(快速函数)可以不使用反射进行调用,这将提高性能,但丢失了参数的类型。
// 只要函数或方法的签名为下面的一种,那么就可以作为Fast functions使用。
/*
func(...interface{}) interface{}
func(...interface{}) (interface{}, error)
*/
type Env2 map[string]interface{}

// !!!!!!! 还能这么玩 !!!!!!! Env2是一个map~~~
func (Env2) FastMethod(args ...interface{}) interface{} {
    //lens := len(args)
    return fmt.Sprintf("Hello, %v, 欢迎来到 ", args)
}
func TestT5(t *testing.T) {
    env := Env2{
        "fastFunc":  func(args ...interface{}) interface{} { return fmt.Sprintf("%v World!", args) },
        "worldName": "git",
        "name":      "whw",
        "age":       22,
    }
    // Notice 注意这里的写法
    out, err := expr.Eval("FastMethod(name,age) + fastFunc(worldName)", env)
    if err != nil {
        panic(err)
    }
    fmt.Println("out: ", out) // out:  Hello, [whw 22], 欢迎来到 [git] World!
}

// notice: 错误返回, 如果函数或方法返回非nil的error,那么这个错误将返回给其对应的调用者。
func doubleFunc(i int) (int, error) {
    if i < 0 {
        return 0, errors.New("value can not be less than zero!")
    }
    return i * 2, nil
}
func TestT6(t *testing.T) {
    env := map[string]interface{}{
        "foo":    -1,
        "double": doubleFunc,
    }
    // This `err` will be the one returned from `double` function.
    // err.Error() == "value cannot be less than zero"
    out, err := expr.Eval("double(foo)", env)
    if err != nil {
        fmt.Println("err: ", err.Error()) // err:  value can not be less than zero!
    } else {
        fmt.Println("out: ", out)
    }
}

expr_higher_test

package expr_practice

// TODO 高阶使用
// https://czyt.tech/post/golang-expr-uncompleted-reference/#%e9%ab%98%e9%98%b6%e4%bd%bf%e7%94%a8

// TODO 性能
// https://czyt.tech/post/golang-expr-uncompleted-reference/#%e6%80%a7%e8%83%bd

// TODO 重用虚拟机
// https://czyt.tech/post/golang-expr-uncompleted-reference/#reuse-vm

// TODO 避免使用反射
// https://czyt.tech/post/golang-expr-uncompleted-reference/#reduced-use-of-reflect

// TODO 方法的替换
// https://czyt.tech/post/golang-expr-uncompleted-reference/#%e6%96%b9%e6%b3%95%e7%9a%84%e6%9b%bf%e6%8d%a2

my_test

package expr_practice

import (
    "fmt"
    "github.com/antonmedv/expr"
    "math"
    "testing"
)

// notice 结构体方法/对象方法 对象方法必须是导出的
type User struct {
    Name string
    Age  int
}

func TestM1(t *testing.T) {

    mp := map[string]interface{}{
        "foo":     1,
        "bar":     2,
        "name":    "whw",
        "n":       "w",
        "b1":      "w",
        "big_num": 10000,
        "array":   []int{1, 2, 3, 4, 5},
    }
    // 各种运算符
    output1, _ := expr.Eval("foo > bar", mp)
    fmt.Println("output1: ", output1) // false

    // 闭区间!
    output2, _ := expr.Eval("foo in 1..3 and bar in 1..2", mp)
    fmt.Println("out2: ", output2) // true

    // in 里面也是map中的key
    out3, _ := expr.Eval("name in [foo, bar, name]", mp)
    fmt.Println("out3: ", out3) // true

    // 带计算
    out4, _ := expr.Eval("foo > 0.3 * 2", mp)
    fmt.Println("out4: ", out4) // true

    // 多个条件组合
    out5, _ := expr.Eval("(foo > 0.3 * 2) and (name in [foo, bar])", mp)
    fmt.Println("out5: ", out5) // false

    // 数字分割符
    out6, _ := expr.Eval("big_num == 10_000", mp)
    fmt.Println("out6: ", out6) // true

    // 字符串运算符
    /*
        + (concatenation)
        matches (regex match)
        contains (string contains)
        startsWith (has prefix)
        endsWith (has suffix)
    */
    code7 := `"name" matches "^N"`
    out7, _ := expr.Eval(code7, mp)
    fmt.Println("out7: ", out7) // false
    code8 := `"name" contains "am"`
    out8, _ := expr.Eval(code8, mp)
    fmt.Println("out8: ", out8) // true
    out9, _ := expr.Eval("name + n", mp)
    fmt.Println("out9: ", out9) // whww
    out10, _ := expr.Eval("name startsWith b1", mp)
    fmt.Println("out10: ", out10) // true
    // Notice 三元运算!!!
    code11 := `foo >= 1 ? "yes":"no"`
    out11, _ := expr.Eval(code11, mp)
    fmt.Printf("out11: %v, %T \n", out11, out11) // yes, string
    code12 := `foo < 1 ? 22:66`
    out12, _ := expr.Eval(code12, mp)
    fmt.Printf("out12: %v, %T \n", out12, out12) // 66, int
    // Notice 注意整数溢出 int值超过maxInt会返回nil!
    fmt.Println("maxInt: ", math.MaxInt) // 9223372036854775807
    code13 := `foo < 1 ? 22:9223372036854775808`
    out13, _ := expr.Eval(code13, mp)
    fmt.Printf("out13: %v, %T \n", out13, out13) // nil, nil

    // 切片
    out14, _ := expr.Eval(`array[:] == array`, mp)
    fmt.Println("out14: ", out14) // true
    out15, _ := expr.Eval(`array[:4] == [1,2,3,4]`, mp)
    fmt.Println("out15: ", out15) // false // TODO ?????内置的规则怎么切的???

    // 内置函数 TODO ~~~~~~
    /*
                len (length of array, map or string)
                all (will return true if all element satisfies the predicate)
                none (will return true if all element does NOT satisfies the predicate)
                any (will return true if any element satisfies the predicate)
                one (will return true if exactly ONE element satisfies the predicate)
                filter (filter array by the predicate)
                map (map all items with the closure)
                count (returns number of elements what satisfies the predicate)
            TODO 怎么举结构体的例子?????
        (1)确保所有推文少于 280 个字符: all(Tweets, {.Size < 280})
        (2)确保只有一位获胜者: one(Participants, {.Winner})
    */

    // 闭包 TODO ~~~~~~
    /*
        只有内置函数才允许闭包。 要访问当前项目,请使用 # 符号。
        map(0..9, {# / 2})

        如果数组的项是 struct,则可以使用省略的 # 符号访问 struct 的字段(#.Value 变为 .Value)。
        filter(Tweets, {len(.Value) > 280})
    */
}

~~~

posted on 2022-11-05 19:37  江湖乄夜雨  阅读(902)  评论(0编辑  收藏  举报