首页 > 其他分享 >expr包的使用

expr包的使用

时间:2022-11-05 19:58:50浏览次数:40  
标签:err expr fmt Eval 使用 Println foo

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})
    */
}

~~~

标签:err,expr,fmt,Eval,使用,Println,foo
From: https://www.cnblogs.com/paulwhw/p/16860931.html

相关文章

  • 【微信小程序】view | scroll | swiper 的使用
    目录1.view的使用2.scroll的使用3.swiper的使用4.补充wx:for的使用1.view的使用viewtest.wxml<!--hover-class:点击后的样式hover-start-time:按下多久后出现样式,单......
  • Leetcode第1106题:解析布尔表达式(Parsing a boolean expression)
    解题思路看到表达式求解,自然想到栈。从左至右遍历布尔表达式expression,对于不同类型字符,进行不同操作:逗号,,跳过该字符;不是逗号,和右括号),入栈;如果是右括号),则一个表......
  • React使用Antd自定义主题报错
    安装包"customize-cra":"^1.0.0","customize-cra-less-loader":"^2.0.0","less":"^4.1.3","less-loader":"^11.1.0",修改config-overrides.jsconst{override......
  • wait和notify方法的使用
    wait和notify方法用来实现一个线程需要等待另一个线程的执行结果的场景。wait:让当前线程在Monitor对象上等待,变成Waiting状态notify:唤醒Monitor对象上等待的一个线程......
  • Windows下安装及卸载程序可用的添加和删除当前路径到环境变量的bat脚本以及如何和inno
    文章目录​​1.安装bat脚本-install.bat(将当前路径添加到环境变量中)​​​​2.卸载bat脚本-uninstall.bat(搜索当前路径并删除)​​​​3.innosetup添加安装和卸载时执行......
  • moco搭建和使用
    一、环境安装见:moco环境安装这里安装的目前最新:moco-runner-1.3.0-standalone.jar,jdk-19_windows-x64_bin.exe,jdk环境变量配置好moco地址:https://github.com/dreamhead/......
  • QString的一些使用技巧
    简介QString字符串被每个GUI程序所使用,不仅是用户界面,还有数据结构。C++原生提供两种字符串:传统的C风格以'\0'结尾的字符数组和std::string类。与这些不同,QString使......
  • 解决在idea中使用springMvc向mysql写入中文数据乱码
    相关设置:1、idea编码格式设置:   2、MySQL的相关编码格式设置:修改前编码:无用操作:之前通过命令行修改编码格式:setcharacter_set_client=utf8......
  • 野花--input获取焦点,改变父元素,改变兄弟元素,不使用js来实现
    :focus-within:focus-within是一个CSS伪类,表示一个元素获得焦点,或该元素的后代元素获得焦点。换句话说,元素自身或者它的某个后代匹配:focus伪类。(shadowDOM树(en-U......
  • 关于markdown的使用
    关于markdown的学习​ 第一次写博客,那就来记录一下Markdown的语法。1.标题通过#+空格+标题实现,#的数量表示几级标题,#最多不能超过六个一级标题二级标题三......