github.com/expr-lang/expr@v1.16.9/docs/getting-started.md (about) 1 # Getting Started 2 3 **Expr** is a simple, fast and extensible expression language for Go. It is 4 designed to be easy to use and integrate into your Go application. Let's delve 5 deeper into its core features: 6 7 - **Memory safe** - Designed to prevent vulnerabilities like buffer overflows and memory leaks. 8 - **Type safe** - Enforces strict type rules, aligning with Go's type system. 9 - **Terminating** - Ensures every expression evaluation cannot loop indefinitely. 10 - **Side effects free** - Evaluations won't modify global states or variables. 11 12 Let's start with a simple example: 13 14 ```go 15 program, err := expr.Compile(`2 + 2`) 16 if err != nil { 17 panic(err) 18 } 19 20 output, err := expr.Run(program, nil) 21 if err != nil { 22 panic(err) 23 } 24 25 fmt.Print(output) // 4 26 ``` 27 28 Expr compiles the expression `2 + 2` into a bytecode program. Then we run 29 the program and get the output. 30 31 :::tip 32 In performance-critical applications, you can reuse the compiled program. Compiled programs are safe for concurrent use. 33 **Compile once** and run **multiple** times. 34 ::: 35 36 The `expr.Compile` function returns a `*vm.Program` and an error. The `expr.Run` function takes a program and an 37 environment. The environment is a map of variables that can be used in the expression. In this example, we use `nil` as 38 an environment because we don't need any variables. 39 40 41 Now let's pass some variables to the expression: 42 43 ```go 44 env := map[string]any{ 45 "foo": 100, 46 "bar": 200, 47 } 48 49 program, err := expr.Compile(`foo + bar`, expr.Env(env)) 50 if err != nil { 51 panic(err) 52 } 53 54 output, err := expr.Run(program, env) 55 if err != nil { 56 panic(err) 57 } 58 59 fmt.Print(output) // 300 60 ``` 61 62 Why do we need to pass the environment to the `expr.Compile` function? Expr can be used as a type-safe language. 63 Expr can infer the type of the expression and check it against the environment. 64 65 Here is an example: 66 67 ```go 68 env := map[string]any{ 69 "name": "Anton", 70 "age": 35, 71 } 72 73 program, err := expr.Compile(`name + age`, expr.Env(env)) 74 if err != nil { 75 panic(err) // Will panic with "invalid operation: string + int" 76 } 77 ``` 78 79 Expr can work with any Go types: 80 81 ```go 82 env := map[string]any{ 83 "greet": "Hello, %v!", 84 "names": []string{"world", "you"}, 85 "sprintf": fmt.Sprintf, 86 } 87 88 code := `sprintf(greet, names[0])` 89 90 program, err := expr.Compile(code, expr.Env(env)) 91 if err != nil { 92 panic(err) 93 } 94 95 output, err := expr.Run(program, env) 96 if err != nil { 97 panic(err) 98 } 99 100 fmt.Print(output) // Hello, world! 101 ``` 102 103 Also, Expr can use a struct as an environment. Methods defined on the struct become functions. 104 The struct fields can be renamed with the `expr` tag. 105 106 Here is an example: 107 108 ```go 109 type Env struct { 110 Posts []Post `expr:"posts"` 111 } 112 113 func (Env) Format(t time.Time) string { 114 return t.Format(time.RFC822) 115 } 116 117 type Post struct { 118 Body string 119 Date time.Time 120 } 121 122 func main() { 123 code := `map(posts, Format(.Date) + ": " + .Body)` 124 125 program, err := expr.Compile(code, expr.Env(Env{})) 126 if err != nil { 127 panic(err) 128 } 129 130 env := Env{ 131 Posts: []Post{ 132 {"Oh My God!", time.Now()}, 133 {"How you doin?", time.Now()}, 134 {"Could I be wearing any more clothes?", time.Now()}, 135 }, 136 } 137 138 output, err := expr.Run(program, env) 139 if err != nil { 140 panic(err) 141 } 142 143 fmt.Print(output) 144 } 145 ``` 146 147 The compiled program can be reused between runs. 148 149 ```go 150 type Env struct { 151 X int 152 Y int 153 } 154 155 program, err := expr.Compile(`X + Y`, expr.Env(Env{})) 156 if err != nil { 157 panic(err) 158 } 159 160 output, err := expr.Run(program, Env{1, 2}) 161 if err != nil { 162 panic(err) 163 } 164 165 fmt.Print(output) // 3 166 167 output, err = expr.Run(program, Env{3, 4}) 168 if err != nil { 169 panic(err) 170 } 171 172 fmt.Print(output) // 7 173 ``` 174 175 :::tip 176 For one-off expressions, you can use the `expr.Eval` function. It compiles and runs the expression in one step. 177 ```go 178 output, err := expr.Eval(`2 + 2`, env) 179 ``` 180 :::