Wing 语言 math.sin 正弦函数实战:从边界断言到 hangar 快照测试

原创2026-10-13 19:04:381,627 阅读
文章标签:编程语言编译器云原生语言运行时

Wing 语言 math.sin 正弦函数实战:从边界断言到 hangar 快照测试

本文以 Wing 标准库 math 模块中的正弦函数 math.sin 为核心,结合仓库中的 SDK 测试用例 sin.test.w、底层实现 math.ts 以及 hangar 测试框架的 快照输出,完整讲解 math.sin 的调用方式、边界行为、运行测试的方法,并深入剖析 Wing 的 test 关键字、simulator 测试流程与快照校验机制。读完本文,你将能在自己的 Wing 项目中正确使用 math.sin 及配套三角函数,并理解 SDK 测试是如何被 hangar 自动采集与快照验证的。

math.sin 是什么:签名与语义

math.sin 是 Wing 标准库 math 模块(SDK 中对应 packages/@winglang/sdk/src/math/math.ts 的 Util 类)提供的三角函数之一,用于计算一个数的正弦值。它的函数签名在官方 API 参考文档 docs/api/04-standard-library/math/api-reference.md 中定义为:

bring math;

math.sin(value: num);

要点说明:

  • 参数类型:value 是必填的 num(Wing 中的数值类型),表示以**弧度(radians)**为单位的角度;
  • 返回值:返回该角度的正弦值(num);
  • 使用前提:必须先通过 bring math; 引入 math 模块才能调用;
  • 调用形式:math.sin 是 Util 类上的静态方法,因此在 Wing 代码中以 math.sin(...) 直接调用,无需实例化对象。

从源码结构看,Util 类还导出了大量数学工具方法,包括绝对值、取整、对数、随机数、均值、组合数等,本文聚焦其中的正弦函数及其测试链路。

从 SDK 测试用例看 sin 的边界行为

仓库中的 SDK 数学测试目录 tests/sdk_tests/math/ 下共有 33 个针对 math 模块的测试文件(abs、acos、sin、tan、factorial 等)。其中 sin.test.w 完整覆盖了 math.sin 的核心边界场景,全文如下:

bring math;

assert(math.sin(-0) == -0);
assert(math.sin(0) == 0);
assert(math.sin(1) == 0.8414709848078965);
assert(math.sin(-5) == 0.9589242746631385);
assert(math.sin(math.PI / 2) == 1);

test "inflight sine" {
  assert(math.sin(-0) == -0);
  assert(math.sin(0) == 0);
  assert(math.sin(1) == 0.8414709848078965);
  assert(math.sin(-5) == 0.9589242746631385);
  assert(math.sin(math.PI / 2) == 1);
}

该文件一次覆盖了五个关键事实,每个断言都值得逐条分析:

断言 期望值 语义说明
math.sin(-0) == -0 -0(负零) 负零的符号被保留,体现 IEEE 754 浮点语义;若写成 == 0 虽也能通过(-0 == 0),但 -0 的精确返回体现了底层实现直接透传 JavaScript Math.sin 的行为
math.sin(0) == 0 0 零弧度正弦为 0
math.sin(1) == 0.8414709848078965 0.8414709848078965 1 弧度(约 57.3°)的正弦值,断言直接写死完整精度,防止实现回归
math.sin(-5) == 0.9589242746631385 0.9589242746631385 负角度输入:sin(-5) ≈ 0.9589,验证负参数路径
math.sin(math.PI / 2) == 1 1 90°(π/2 弧度)正弦恰为 1,同时验证了常量 math.PI 与 sin 的联用

测试文件还演示了 Wing 特有的双相位执行模型:文件顶层的 assert 在**preflight(预飞行/编译期)**阶段直接执行,作为编译期的数学验证;而 test "inflight sine" { ... } 声明的测试块则在测试运行阶段(simulator 或云端)执行,验证 math.sin 在 inflight(运行时) 环境下同样可用。也就是说,同一个正弦函数在两种执行相位下都经过了断言校验。

底层实现:Util.sin 如何映射到 Math.sin

math.sin 的实现非常薄,它直接委托给 JavaScript 引擎的内置 Math.sin。在 packages/@winglang/sdk/src/math/math.ts 中可以找到:

/**
 * Returns the sine of a number in radians.
 * @param value A number representing an angle in radians.
 */
public static sin(value: number): number {
  return Math.sin(value);
}

由此可以得出几个实现层面的结论:

  • 精度一致性:sin.test.w 中断言的 0.8414709848078965 等浮点结果,正是 JavaScript Math.sin 在 IEEE 754 双精度下的计算结果,测试因此可以直接与底层引擎行为对齐;
  • 负零行为:Math.sin(-0) 在 JavaScript 中返回 -0,所以 Util.sin 透传后也保留负零,这正是 assert(math.sin(-0) == -0) 能成立的根本原因;
  • 纯计算、无云资源:math.sin 不依赖任何云服务。这一点在 hangar 的 tf-aws 编译快照 sin.test.w_compile_tf-aws.md 中得到印证——编译到 tf-aws 目标后生成的 main.tf.json 中只有 aws provider 的空配置,没有任何基础设施资源。也就是说,纯数学运算不会在云上产生任何资源开销,这是 math 模块区别于 cloud.Bucket、cloud.Queue 等资源类模块的关键特征。

Util 类还通过 _toInflightType() 与 InflightClient.forType(...) 配合,使这些静态数学方法可以在 inflight 闭包中被引用,这也是 test "inflight sine" 能在运行时调用 math.sin 的基础设施。

配套常量与三角函数族

math.sin 常与 math 模块的其他常量和三角函数配合使用,测试用例中的 math.PI / 2 就是一个典型例子。Util 类提供四个数学常量(均在 math.ts 中定义):

常量 值 说明
math.PI Math.PI 圆周率 π,圆周长与直径之比
math.TAU 2 * Math.PI 圆周率 τ,圆周长与半径之比(2π)
math.E Math.E 自然常数 e,约等于 2.71828
math.INF Number.POSITIVE_INFINITY 正无穷

与 sin 同族的三角函数还包括:

  • 基础三角:math.cos(value)、math.tan(value)(均以弧度输入);
  • 反三角:math.asin(value)、math.acos(value)(要求 -1 ≤ value ≤ 1,越界会抛出 "Input value must be between -1 and 1, inclusive.")、math.atan(value)、math.atan2(y, x);
  • 余割族:math.sec(value)(1 / cos)、math.csc(value)(1 / sin)、math.cot(value)(1 / tan),以及对应的反函数 math.asec、math.acsc、math.acot(后两者要求 |value| ≥ 1);
  • 角度换算:math.degreesToRadians(degrees) 与 math.radiansToDegrees(radians),可用于将日常使用的角度制转换为 sin 所需的弧度制。

完整的函数签名与参数说明可见 docs/api/04-standard-library/math/api-reference.md,其中每个函数都给出了可直接复制的 Wing 调用示例。

运行测试:wing test 与快照输出解读

在 simulator 中运行

将 sin.test.w 放到任意目录,执行(--target sim 是默认目标,可省略):

wing test sin.test.w --target sim

对应的 hangar 快照 sin.test.w_test_sim.md 记录了标准输出:

pass ─ sin.test.wsim » root/Default/test:inflight sine

Tests 1 passed (1)
Snapshots 1 skipped
Test Files 1 passed (1)
Duration <DURATION>

逐行解读这份输出:

  • pass ─ sin.test.wsim » root/Default/test:inflight sine:测试用例 inflight sine 通过,运行目标是 sin.test.wsim(即该文件编译成的 simulator 应用),测试路径为 root/Default/test:inflight sine;
  • Tests 1 passed (1):共 1 个测试全部通过;
  • Snapshots 1 skipped:runner 的测试输出中有一项快照被跳过(测试未涉及快照比对场景,属正常现象);
  • Duration <DURATION>:<DURATION> 是 hangar 在比对快照前对动态耗时字段做的归一化替换——由于每次运行耗时不同,hangar 用占位符代替实际时间,从而保证快照内容可稳定比对。

关于 test 关键字的更多用法(测试隔离执行、-o/--output-file 导出 JSON 结果、tf-aws 云端运行、--no-clean 保留资源等),可参考 docs/docs/02-concepts/04-tests.md。

在 tf-aws 目标上编译

同一份测试还会被 hangar 编译到 tf-aws 目标,快照 sin.test.w_compile_tf-aws.md 中的 main.tf.json 输出为:

{
  "//": {
    "metadata": {
      "backend": "local",
      "stackName": "root"
    },
    "outputs": {}
  },
  "provider": {
    "aws": [
      {}
    ]
  }
}

这份空壳 Terraform 配置再次证明:math.sin 是纯函数计算,编译到云目标时不会产生任何 AWS 资源定义。如果你在测试代码里只做数学运算,云端部署的 Terraform 状态文件就是如此干净——只有 provider 声明,没有资源块。

hangar 快照测试机制:快照如何生成与校验

上面两份 .md 快照并非手写维护,而是由 Wing 的测试编排工具 hangar(位于 tools/hangar)自动生成与校验的。整个过程可以分为三条链路:

1. 测试用例生成:脚本 tools/hangar/src/generate_tests.ts 会递归扫描 tests/sdk_tests/ 等测试目录,为每个 .w 文件生成对应的 vitest 用例,例如对 sin.test.w 生成两类测试:

  • wing compile -t tf-aws:执行编译并校验 Terraform 产物快照;
  • wing test -t sim:在 simulator 上运行测试并校验 stdout 快照。

生成器还支持读取 .w 文件头部的 meta 注释(parseMetaCommentFromPath)来决定是否跳过某类目标,并自动处理 target、node_modules 等目录的排除。

2. 快照存放:快照统一沉淀在 tools/hangar/snapshots/test_corpus/sdk_tests/math/ 目录,命名规则为 <文件名>_compile_tf-aws.md 与 <文件名>_test_sim.md,分别对应编译产物与 sim 测试输出。sin.test.w 的两个快照正是本文引用的这两份文件。

3. 动态内容归一化:为了让快照在每次 CI 运行中保持字节级稳定,hangar 会对 <DURATION> 这类运行时差异字段做占位替换,因此快照可以长期作为回归基线:一旦 math.sin 的实现或测试断言发生变化(例如浮点结果被改动),CI 就会通过快照比对立即暴露差异。

从这层机制可以看出,sin.test.w 的测试并不只是"写几个断言",它同时承担了三重职责:preflight 期的数学正确性校验、inflight 期的运行时行为校验、以及 tf-aws 编译产物的回归守护——这正是 Wing SDK 质量保障链路的一部分。

小结

通过 math.sin 这个入口,我们完整走通了一条从「语言 API → 测试用例 → 底层实现 → 测试编排与快照」的链路:

  • 使用层面:bring math; 后调用 math.sin(弧度值) 即可,配合 math.PI、math.degreesToRadians 可以方便地处理角度换算;
  • 语义层面:sin 直接透传 JavaScript Math.sin,天然继承 IEEE 754 的精度与负零行为,且因为是纯计算,编译到任何云目标都不会产生基础设施资源;
  • 测试层面:Wing 的 test 关键字支持 preflight 断言与 inflight 测试块,wing test --target sim 即可本地验证,而 hangar 会通过 __snapshots__ 快照对 sim 输出与 tf-aws 编译产物做自动化回归校验。

如果你需要在 Wing 中做三角运算、波动模拟或任何角度相关的数值计算,math.sin 及配套的 cos、tan、反三角与角度换算函数,就是标准库给出的官方答案。

登录后查看全文
wing