Skip to main content
Version: v1.16

Functions

Expr comes with a set of builtin functions, but you can also define your own functions.

The easiest way to define a custom function is to add it to the environment.

env := map[string]any{
"add": func(a, b int) int {
return a + b
},
}

Or you can use functions defined on a struct:

type Env struct{}

func (Env) Add(a, b int) int {
return a + b
}
info

If functions are marked with ConstExpr option, they will be evaluated at compile time.

The best way to define a function from a performance perspective is to use a Function option.

atoi := expr.Function(
"atoi",
func(params ...any) (any, error) {
return strconv.Atoi(params[0].(string))
},
)

program, err := expr.Compile(`atoi("42")`, atoi)

Type checker sees the atoi function as a function with a variadic number of arguments of type any, and returns a value of type any. But, we can specify the types of arguments and the return value by adding the correct function signature or multiple signatures.

atoi := expr.Function(
"atoi",
func(params ...any) (any, error) {
return strconv.Atoi(params[0].(string))
},
new(func(string) int),
)

Or we can simply reuse the strconv.Atoi function as a type:

atoi := expr.Function(
"atoi",
func(params ...any) (any, error) {
return strconv.Atoi(params[0].(string))
},
strconv.Atoi,
)

It is possible to define multiple signatures for a function:

toInt := expr.Function(
"toInt",
func(params ...any) (any, error) {
switch params[0].(type) {
case float64:
return int(params[0].(float64)), nil
case string:
return strconv.Atoi(params[0].(string))
}
return nil, fmt.Errorf("invalid type")
},
new(func(float64) int),
new(func(string) int),
)