Skip to main content
Environment 是 Fluxon 执行期的“作用域 + 符号表”。解释器与编译执行引擎都会基于同一个 Environment 完成变量读写、 函数调用与扩展函数分派(target::method(...))。 它管理的核心要素:
  • 函数:系统函数(含命名空间函数)。
  • 扩展函数:上下文调用 target::method(...)
  • 变量:根变量(全局)与局部变量(函数调用作用域)。
  • 上下文目标target 槽位(由 :: 调用临时写入)。
Environment 通常通过 FluxonRuntime#getInstance().newEnvironment() 创建。注册新的函数/扩展/变量后, 重新创建环境以刷新运行时缓存。

Root 与子环境

  • 根环境(root):持有函数映射、扩展函数映射、根变量映射,以及运行时生成的缓存结构(用于加速调用分派)。
  • 子环境(child):用于函数调用作用域,只存放局部变量数组与(可选的)局部变量名;通过 root 引用共享根数据。

函数解析

普通函数通过 Environment#getFunction(name) 在根函数表中查找;不存在会抛出 FunctionNotFoundError 命名空间函数(如 fs:time)需要脚本先 import 'fs:time' 才会被解析到(见 术语表)。

扩展函数解析(target::method

扩展函数的匹配依赖 target 的宿主类型:
  • 解析器在可优化的场景下会为调用点生成 extensionPositionIndex,运行时会使用 root.dispatchTables[index] 快速解析。
  • 对于动态注册或无法提前编号的调用点,会回退到 root.extensionFunctions.get(name) 的映射,并按“精确类型 → isAssignableFrom”顺序匹配。
如果你在运行中动态注册了扩展函数,旧的 Environment 可能不会包含新的派发表缓存;建议在注册完成后重新 newEnvironment()

变量与索引

变量访问在运行时以“索引”为主:
  • index = -1:根变量(保存在 rootVariables)。
  • index >= 0:局部变量(保存在 localVariables[index]),必要时沿 parent 链回溯。
当索引越界且不存在 parent 时会抛出 VariableNotFoundError,并附带 localVariableNames 以便定位问题。

上下文目标 target

上下文调用会把左侧表达式写入 Environment#target,再执行右侧函数/扩展;执行完成后解释器会恢复旧的 target

调试与枚举

  • Environment#getRootFunctions():当前系统函数表。
  • Environment#getRootExtensionFunctions():当前扩展函数映射(类型 → Function)。
  • Environment#getRootVariables():当前根变量表(含宿主注入的对象)。
  • FunctionContext#toString():定位一次调用的 target 与参数。

外部变量注入

Fluxon 提供两种方式向脚本注入外部变量:根变量(RootVariable)参数(Parameter)

对比

特性根变量参数
定义时机运行时编译期
存储方式HashMap 查找数组索引
类型无类型(Object)强类型(double、long、Object)
性能中等
共享范围全局(所有 Environment 共享)每个 Environment 独立

根变量

根变量通过 HashMap 存储,适合全局常量或工具对象:
// 方式一:通过 FluxonRuntime 注册(全局共享)
FluxonRuntime.getInstance().registerVariable("config", configObject);

// 方式二:在 Environment 中定义
env.defineRootVariable("logger", loggerInstance);
env.setRootVariable("logger", newLoggerInstance);  // 修改
Object logger = env.getRootVariable("logger");     // 读取
脚本中通过 & 引用访问:
&config :: get("timeout")
&logger :: info("message")

参数

参数通过数组索引存储,适合高频调用场景:
// 编译期定义(必须指定类型)
CompilationContext ctx = new CompilationContext(source);
ctx.defineParameter("rate", double.class);
ctx.defineParameter("name", String.class);
CompiledScript script = ctx.compile();

// 运行时绑定
Environment env = script.newEnvironment();
env.setParameter("rate", 0.15);
env.setParameter("name", "Alice");
script.execute(env);

// 换值再执行(无需重新编译)
env.setParameter("rate", 0.20);
script.execute(env);

选择建议

  • 根变量:全局配置、工具对象、不常变化的数据
  • 参数:需要高频变化的输入值、性能敏感场景
参数必须在编译前定义,编译后无法新增;根变量可随时添加。

参数绑定 API

Environment 参数方法

方法说明
setParameter(name, value)设置对象类型参数值。
setParameter(name, double)设置 double 类型参数值(避免装箱)。
setParameter(name, long)设置 long 类型参数值。
getParameterInfo(name)获取参数的元信息(类型、索引)。

脚本中使用

参数通过 & 引用访问,与普通变量语法一致:
total = &price * (1 + &rate)
greeting = "Hello, " + &name

FunctionContext 参数获取

在函数实现中,通过 FunctionContext 获取参数:
方法说明
getRef(index)获取指定索引的参数原始引用。
getInt(index)获取 int 类型参数。
getLong(index)获取 long 类型参数。
getDouble(index)获取 double 类型参数。
getAsDouble(index)将任意数值参数转换为 double。
getString(index)获取 String 类型参数。
import static org.tabooproject.fluxon.runtime.FunctionSignature.returns;
import org.tabooproject.fluxon.runtime.Type;

runtime.registerFunction("multiply", returns(Type.D).params(Type.D, Type.D), ctx -> {
    double a = ctx.getAsDouble(0);
    double b = ctx.getAsDouble(1);
    ctx.setReturnDouble(a * b);
});

相关链接