Package calc provides advanced parsers for floats, ints, ..., based on Go constants calculator.
When it comes to manually writing numbers, the usual literal format are not always the easiest.
How do you write the equivalent of 1 day but in seconds? 24*60*60
is probably easier than
figuring out it is 86400
. Why, then asking your users to provide CLI arguments (or inputs in a textfield)
as a number, when you could easily ask them to enter it as a basic formula?
Go has figure that out, and has created a powerful constants systems that can be used to higly improve parsing basic types.
func Bool
func Bool(expr string) (bool, error)
Bool computes the bool expression.
func Complex128
func Complex128(expr string) (c complex128, err error)
Complex128 computes the complex expression.
func Complex64
func Complex64(expr string) (c complex64, err error)
Complex64 computes the complex expression.
func Float32
func Float32(expr string) (float32, error)
Float32 computes the float expression.
func Float64
func Float64(expr string) (float64, error)
Float64 computes the float expression.
func Int
func Int(expr string) (int64, error)
Int computes the int expression.
Using [calc.Int] you can parse basic literals, exactly as [strconv.ParseInt] can do, and evaluate more advanced expressions.
The example below showcases some more posibilities.
package main
import (
"fmt"
"strconv"
"github.com/etnz/calc"
)
func main() {
exp := "2"
v, _ := calc.Int(exp)
fmt.Println("Literal:", exp, "=", v)
// For comparison:
v, _ = strconv.ParseInt(exp, 10, 64)
fmt.Println("Package strconv:", exp, "=", v)
exp = "2+2"
v, _ = calc.Int(exp)
fmt.Println("Algebra:", exp, "=", v)
exp = "1<<100 + 2 - 1<<100"
v, _ = calc.Int(exp)
fmt.Println("Safe overflow:", exp, "=", v)
exp = "0777"
v, _ = calc.Int(exp)
fmt.Println("Octal:", exp, "=", v)
exp = "0xFF"
v, _ = calc.Int(exp)
fmt.Println("Hex:", exp, "=", v)
exp = "0b1010 ^ 0b0101"
v, _ = calc.Int(exp)
fmt.Println("Binary:", exp, "=", v)
exp = "0xFF - 0b11111110"
v, _ = calc.Int(exp)
fmt.Println("Mixed:", exp, "=", v)
}
Output:
Literal: 2 = 2
Package strconv: 2 = 2
Algebra: 2+2 = 4
Safe overflow: 1<<100 + 2 - 1<<100 = 2
Octal: 0777 = 511
Hex: 0xFF = 255
Binary: 0b1010 ^ 0b0101 = 15
Mixed: 0xFF - 0b11111110 = 1
func String
func String(expr string) (string, error)
String computes the string expression.
func Uint
func Uint(expr string) (uint64, error)
Uint computes the int expression.
type Scope
type Scope struct { ... }
Scope contains a set of [constant.Value] that can be referenced by their name.
zero type is valid.
func (*Scope) Assign
func (s *Scope) Assign(name, expr string) error
Assign evaluates 'expr' and assign its value to the variable 'name'.
If the variable 'name' already exists, its value is not changed.
When writing expressions it can be handy to use predefined constants. It is possible to prepare a [calc.Scope] with predefined variables.
package main
import (
"fmt"
"github.com/etnz/calc"
)
func main() {
var (
exp string
v int64
c calc.Scope
)
// prepare the Scope with useful constants.
c.Assign("s", "1") // 1 second
c.Assign("m", "60*s")
c.Assign("h", "60*m")
c.Assign("d", "24*h")
c.Assign("w", "7*d")
// Constants in Go are powerful:
// expression can use floating point and still lead
// to an exact integer.
exp = "2.5*d"
v, _ = c.Int(exp)
fmt.Println("Time:", exp, "=", v)
exp = "2*d + 4*h"
v, _ = c.Int(exp)
fmt.Println("Time:", exp, "=", v)
// Constants in Go are powerful 2
// It doesn't matter how you have defined them.
exp = "2.5*s"
f, _ := c.Float64(exp)
fmt.Println("Float:", exp, "=", f)
}
Output:
Time: 2.5*d = 216000
Time: 2*d + 4*h = 187200
Float: 2.5*s = 2.5
func (*Scope) AssignValue
func (s *Scope) AssignValue(name string, v any)
AssignValue directly assign the runtime value 'v' to the variable 'name'. 'v' must be one of:
float64
float32
complex128
complex64
int64
int32
int16
int8
int
uint64
uint32
uint16
uint8
uint
bool
string
If the variable 'name' already exists, its value is not changed.
func (Scope) Bool
func (s Scope) Bool(expr string) (bool, error)
Bool evaluates 'expr' as a bool.
func (Scope) Complex128
func (s Scope) Complex128(expr string) (cplx complex128, err error)
Complex128 evaluates 'expr' as a complex128.
func (Scope) Complex64
func (s Scope) Complex64(expr string) (cplx complex64, err error)
Complex64 evaluates 'expr' as a complex64.
func (Scope) Float32
func (s Scope) Float32(expr string) (float32, error)
Float32 evaluates 'expr' as a float32.
func (Scope) Float64
func (s Scope) Float64(expr string) (float64, error)
Float64 evaluates 'expr' as a float64.
func (*Scope) Import
func (s *Scope) Import(name string, lib *Scope)
Import another [Scope] inside this one.
Exposed variables in 'lib' can be referenced as <name>.<var>
.
Following the rules of Go, only Capitalized variables are exposed.
Nesting Scopes is not supported (by Go).
When writing expressions using variables, it is possible to "pack" them in their own namespace to avoid conflicts.
package main
import (
"fmt"
"github.com/etnz/calc"
)
func main() {
var (
exp string
v int64
c, lib calc.Scope
)
// prepare a library of variables.
lib.Assign("S", "1") // 1 second
lib.Assign("M", "60*S")
lib.Assign("H", "60*M")
lib.Assign("D", "24*H")
// Import that lib as 'time' to make it usable.
c.Import("time", &lib)
exp = "2*time.D + 4*time.H"
v, _ = c.Int(exp)
fmt.Println("Time:", exp, "=", v)
}
Output:
Time: 2*time.D + 4*time.H = 187200
func (Scope) Int
func (s Scope) Int(expr string) (int64, error)
Int evaluates 'expr' as a int64.
func (Scope) String
func (s Scope) String(expr string) (string, error)
String evaluates 'expr' as a string.
func (Scope) Uint
func (s Scope) Uint(expr string) (uint64, error)
Uint evaluates 'expr' as an int64.
Readme created from Go doc with goreadme