- 编程语言
- 编译器
- 云原生
- 语言运行时
【免费下载链接】wing
A programming language for the cloud ☁️ A unified programming model, combining infrastructure and runtime code into one language ⚡
导读
Wing 语言把基础设施定义(preflight)与运行时逻辑(inflight)统一在同一个编程模型中,而lift正是连接两者的桥梁:它负责把 preflight 对象"搬运"进 inflight 闭包,并据此为宿主(如cloud.Function)生成最小权限。本文以仓库中真实的端到端测试用例lift_via_closure.test.w及其编译快照 lift_via_closure.test.w_compile_tf-aws.md 为核心,逐层剖析一个同时包含"合成闭包"与"类闭包"的程序在tf-aws目标上的全部编译产物——包括 inflight client 文件、preflight.cjs与main.tf.json,并结合 SDK 源码讲清_liftMap、_liftedState、liftObject的底层原理。读完本文,你将能读懂 Wing 编译器为闭包生成的 lift 矩阵,理解为何fn2.bucket会被隐式提升(transitive lift),并能用 hangar 快照机制自行验证行为。
一、背景:闭包调用与 lift 是什么
在 Wing 中,闭包(closure)是捕获其词法作用域变量的函数。官方示例见 docs/by-example/16-closures.md,而更关键的是 Wing 的两阶段模型(docs/docs/02-concepts/01-preflight-and-inflight.md):
- preflight:编译期运行一次,生成云基础设施配置;
- inflight:运行时执行的应用逻辑,运行在 Lambda、容器、VM 等计算平台上。
当一个 inflight 闭包引用了 preflight 对象时,该对象被称为"被 lift 的对象"。编译器会自动分析对象上被调用的操作(operation),生成一张"对象 → 操作集合"的映射矩阵(即_liftMap),供宿主(inflight host)配置最小权限。这一过程被官方 RFC 2024-03-14-explicit-lift-qualification.md 定义为:
- 为 inflight 代码中的 preflight 对象生成 inflight client;
- 配置闭包的宿主,使其能安全访问该对象(最小权限授权)。
本文聚焦的测试用例正是围绕"闭包能否像函数一样被调用"这一语言特性展开的,它验证了两种闭包形态:由inflight () => {...}字面量生成的合成闭包(synthetic closure),以及通过类 + inflight 方法定义、实例化后同样可直接调用的类闭包(non-synthetic closure)。
二、测试程序源码解读
测试源码位于 tests/valid/lift_via_closure.test.w,完整代码如下:
bring cloud; let bucket2 = new cloud.Bucket(); let fn = inflight () => { bucket2.put("hello", "world"); }; class MyClosure { pub bucket: cloud.Bucket; new() { this.bucket = new cloud.Bucket(); } inflight handle() { log("handle called"); this.putFile(); } inflight putFile() { log("putFile called"); this.bucket.put("hello", "world"); } pub inflight listFiles(): Array<str> { bucket2.put("b2", "world"); return this.bucket.list(); } } let fn2 = new MyClosure(); test "call synthetic closure class as a function" { fn(); } test "call non-synthetic closure as a function" { fn2(); assert(fn2.bucket.get("hello") == "world"); assert(fn2.listFiles().length == 1); assert(bucket2.get("b2") == "world"); }逐段来看它的设计意图:
bucket2是 preflight 层创建的cloud.Bucket,后续被多个 inflight 闭包捕获;fn是一个合成闭包:inflight () => { bucket2.put("hello", "world"); }。编译器会为它生成一个隐藏的$Closure1资源(见下文preflight.cjs中的AutoIdResource);MyClosure是一个普通(preflight)类:构造函数在 preflight 创建自己的bucket,并定义了三个 inflight 方法handle、putFile、listFiles。其中handle调用了this.putFile()(方法间调用),listFiles既访问了实例字段this.bucket,又捕获了模块级变量bucket2;fn2是MyClosure的实例。在测试中它被直接当作函数调用:fn2(),即调用其handle方法——这正是"非合成闭包作为函数调用"的含义;- 两个
test块分别验证两种闭包调用路径。第二个测试还做了三个断言,用于验证 lift 的传递性:fn2.bucket(实例字段)和bucket2(模块变量)在 inflight 侧都能被正确读写。
三、编译产物全景:hangar 快照的结构
该测试在tf-aws目标上的编译输出被 hangar 固化为快照文件 lift_via_closure.test.w_compile_tf-aws.md。快照的文件头# [lift_via_closure.test.w](https://link.gitcode.com/i/0880409055047e9c6de83a20d8ba1a57) | compile | tf-aws表明其命名约定为<源文件> | <测试场景> | <目标>。
快照正文按文件名分节,共包含 5 个产物:
| 产物文件 | 作用 |
|---|---|
inflight.$Closure1-1.cjs | 合成闭包fn的 inflight client |
inflight.$Closure2-1.cjs | 测试一"call synthetic closure class as a function"的包装闭包 client |
inflight.$Closure3-1.cjs | 测试二"call non-synthetic closure as a function"的包装闭包 client |
inflight.MyClosure-1.cjs | 类MyClosure的 inflight client |
main.tf.json | Terraform(tf-aws)资源定义 |
preflight.cjs | 编译生成的 preflight 入口程序 |
这套快照正是由 hangar 测试框架(tools/hangar/src/utils.ts 中的createMarkdownSnapshot)生成的:它遍历WingCompiler合成出的全部输出文件,按文件名排序后逐段写入 Markdown 代码块。runWingCommand则通过wingBin以--no-update-check --no-analytics <args> <wingFile> -t <platform>的形式调用 CLI。
四、合成闭包 vs 类闭包:inflight client 的两种形态
4.1 合成闭包:捕获列表直接注入模块工厂
inflight.$Closure1-1.cjs是fn的 client:
"use strict"; const $helpers = require("@winglang/sdk/lib/helpers"); const $macros = require("@winglang/sdk/lib/macros"); module.exports = function({ $bucket2 }) { class $Closure1 { constructor($args) { const { } = $args; const $obj = (...args) => this.handle(...args); Object.setPrototypeOf($obj, this); return $obj; } async handle() { (await $bucket2.put("hello", "world")); } } return $Closure1; }关键点:
- 整个模块是一个工厂函数,其形参
{ $bucket2 }就是该闭包的捕获列表(capture list)。所有被 lift 的 preflight 对象都会以$前缀的变量名注入; constructor中const $obj = (...args) => this.handle(...args)并Object.setPrototypeOf($obj, this),把实例变成"可调用对象"——这正是 Wing 中fn()能直接调用handle的底层实现;handle方法内的await $bucket2.put("hello", "world")是运行时真正访问 S3 的调用。
4.2 类闭包:实例字段通过构造参数注入,模块变量仍走捕获列表
inflight.MyClosure-1.cjs展示了类闭包 client 的差异:
module.exports = function({ $bucket2 }) { class MyClosure { constructor($args) { const { $this_bucket } = $args; this.$this_bucket = $this_bucket; const $obj = (...args) => this.handle(...args); Object.setPrototypeOf($obj, this); return $obj; } async handle() { console.log("handle called"); (await this.putFile()); } async putFile() { console.log("putFile called"); (await this.$this_bucket.put("hello", "world")); } async listFiles() { (await $bucket2.put("b2", "world")); return (await this.$this_bucket.list()); } } return MyClosure; }这里出现两条 lift 通道:
- 实例字段(instance field):
this.bucket在 preflight 中被"提升状态"(lifted state),作为构造参数$this_bucket传入,并保存为实例属性。它对应preflight.cjs中MyClosure._liftedState()的返回值(见 5.2 节); - 模块级捕获变量:
bucket2仍通过模块工厂的形参{ $bucket2 }注入——因为listFiles直接引用了模块级变量bucket2。
同时注意handle调用this.putFile()、putFile调用this.$this_bucket.put(...),这些是 inflight 方法间的内部调用,不需要额外的 lift 声明,但会在_liftMap中体现为方法间的依赖传递。
4.3 测试包装闭包:把被测闭包再 lift 一层
inflight.$Closure2-1.cjs与inflight.$Closure3-1.cjs分别是两个test块的包装闭包:
// $Closure2:仅捕获 $fn module.exports = function({ $fn }) { class $Closure2 { async handle() { (await $fn()); } } return $Closure2; }// $Closure3:同时捕获 $bucket2、$fn2、$fn2_bucket module.exports = function({ $bucket2, $fn2, $fn2_bucket }) { class $Closure3 { async handle() { (await $fn2()); $helpers.assert($helpers.eq((await $fn2_bucket.get("hello")), "world"), "fn2.bucket.get(\"hello\") == \"world\""); $helpers.assert($helpers.eq((await $fn2.listFiles()).length, 1), "fn2.listFiles().length == 1"); $helpers.assert($helpers.eq((await $bucket2.get("b2")), "world"), "bucket2.get(\"b2\") == \"world\""); } } return $Closure3; }$Closure3的捕获列表{ $bucket2, $fn2, $fn2_bucket }是最有价值的观察点:$fn2_bucket并不存在于源程序中——它是编译器对fn2.bucket(类实例的字段)做的传递性 lift(transitive lift)。测试代码写的是fn2.bucket.get("hello"),编译器将其拆解为:liftfn2本身(调用handle、listFiles)+ liftfn2.bucket(调用get),并把后者作为独立捕获项注入。这印证了 docs/docs/02-concepts/01-preflight-and-inflight.md 中"lift 过程中编译器会分析被 lift 对象的用法"的描述。
五、preflight.cjs 剖析:lift 矩阵与权限声明的生成
preflight.cjs是 Wing 编译器为整个程序生成的 preflight 入口,其中每个闭包都对应一个 preflight 资源类。它的骨架如下(摘自 lift_via_closure.test.w_compile_tf-aws.md):
const $stdlib = require('@winglang/sdk'); const $platforms = ((s) => !s ? [] : s.split(';'))(process.env.WING_PLATFORMS); const $outdir = process.env.WING_SYNTH_DIR ?? "."; const $wing_is_test = process.env.WING_IS_TEST === "true"; ... class $Root extends $stdlib.std.Resource { constructor($scope, $id) { ... class $Closure1 extends $stdlib.std.AutoIdResource { _id = $stdlib.core.closureId(); ... static _toInflightType() { return ` require("${$helpers.normalPath(__dirname)}/inflight.$Closure1-1.cjs")({ $bucket2: ${$stdlib.core.liftObject(bucket2)}, }) `; } get _liftMap() { return ({ "handle": [ [bucket2, ["put"]], ], "$inflight_init": [ [bucket2, []], ], }); } } ... const bucket2 = globalThis.$ClassFactory.new("@winglang/sdk.cloud.Bucket", cloud.Bucket, this, "Bucket"); const fn = new $Closure1(this, "$Closure1"); const fn2 = new MyClosure(this, "MyClosure"); globalThis.$ClassFactory.new("@winglang/sdk.std.Test", std.Test, this, "test:call synthetic closure class as a function", new $Closure2(this, "$Closure2")); globalThis.$ClassFactory.new("@winglang/sdk.std.Test", std.Test, this, "test:call non-synthetic closure as a function", new $Closure3(this, "$Closure3")); } } const $APP = $PlatformManager.createApp({ outdir: $outdir, name: "lift_via_closure.test", rootConstruct: $Root, isTestEnvironment: $wing_is_test, entrypointDir: process.env['WING_SOURCE_DIR'], rootId: process.env['WING_ROOT_ID'] }); $APP.synth();逐点拆解:
5.1 合成闭包是隐藏的 AutoIdResource
$Closure1继承$stdlib.std.AutoIdResource(见 packages/@winglang/sdk/src/std/resource.ts),其含义是"由编译器自动生成 id 的资源",专门用于 inflight 闭包。构造函数中$helpers.nodeof(this).hidden = true将其标记为隐藏节点,不会出现在应用树中。_id = $stdlib.core.closureId()为每个闭包分配不透明标识(见 packages/@winglang/sdk/src/core/inflight.ts),用于按身份比较闭包。
5.2 类闭包:_liftedState 描述实例字段的提升
MyClosure直接继承Resource,它的特殊之处在于_liftedState():
_liftedState() { return { ...(super._liftedState?.() ?? {}), $this_bucket: $stdlib.core.liftObject(this.bucket), }; }_liftedState返回"需要作为构造参数传给 inflight client 的字段映射"(对应 packages/@winglang/sdk/src/std/resource.ts 中ILiftable._liftedState的注释:Return the fields that need to be passed to the inflight constructor as arguments)。this.bucket经liftObject序列化后,以$this_bucket为键注入 client 构造器——这正是 4.2 节中constructor($args) { const { $this_bucket } = $args; }的来源。同时它的_liftMap为每个 inflight 方法声明了依赖:
get _liftMap() { return ({ "handle": [ [this, ["putFile"]], // handle 依赖自身实例的 putFile ], "putFile": [ [this.bucket, ["put"]], // putFile 依赖 this.bucket.put ], "listFiles": [ [bucket2, ["put"]], // listFiles 依赖模块变量 bucket2.put [this.bucket, ["list"]], // 以及 this.bucket.list ], "$inflight_init": [ [bucket2, []], // 初始化时需引用(无需操作权限) [this.bucket, []], ], }); }注意这里[this, ["putFile"]]表示handle的依赖是"调用自身实例的putFile方法";$inflight_init是特殊操作(常量INFLIGHT_INIT_METHOD_NAME = "$inflight_init",定义于 packages/@winglang/sdk/src/core/lifting.ts),表示无论宿主请求哪些操作,对象本身都必须可用,但它对用户是隐藏的,不会传给onLift/onLiftType。
5.3 传递性 lift 的矩阵表达
$Closure3._liftMap是最能体现"传递性 lift"的部分:
get _liftMap() { return ({ "handle": [ [bucket2, ["get"]], [fn2, [].concat(["handle"], ["listFiles"])], [fn2.bucket, ["get"]], ], "$inflight_init": [ [bucket2, []], [fn2, []], [fn2.bucket, []], ], }); }- 源程序只写了
fn2()、fn2.bucket.get(...)、fn2.listFiles(),编译器据此推导出fn2需要handle与listFiles两个操作,fn2.bucket需要get; - 由于
handle内部又调用putFile,而putFile用到this.bucket.put,理论上权限矩阵会沿依赖图继续传递——SDK 侧的collectLifts(见第六节)正是负责在运行时把这张矩阵展开为完整的对象依赖图。
5.4 环境变量与测试注册
- 编译产物通过
process.env.WING_PLATFORMS(以;分隔的平台列表)、WING_SYNTH_DIR(合成输出目录,默认.)、WING_IS_TEST、WING_SOURCE_DIR、WING_ROOT_ID驱动; $PlatformManager.createApp(...)创建应用并调用$APP.synth()触发资源合成;- 两个测试块被注册为
@winglang/sdk.std.Test资源,其 id 为test:call synthetic closure class as a function与test:call non-synthetic closure as a function,分别挂在$Closure2、$Closure3上。
六、main.tf.json:tf-aws 目标的资源合成
main.tf.json是该程序在tf-aws平台上合成的 Terraform 配置。因为程序中创建了两个cloud.Bucket(bucket2和MyClosure实例字段里的bucket),合成结果包含两个aws_s3_bucket资源及对应的 CORS 配置:
{ "provider": { "aws": [ {} ] }, "resource": { "aws_s3_bucket": { "Bucket": { "//": { "metadata": { "path": "root/Default/Default/Bucket/Default", "uniqueId": "Bucket" } }, "bucket_prefix": "bucket-c88fdc5f-", "force_destroy": false }, "MyClosure_Bucket_874B5056": { "//": { "metadata": { "path": "root/Default/Default/MyClosure/Bucket/Default", "uniqueId": "MyClosure_Bucket_874B5056" } }, "bucket_prefix": "bucket-c8fe564c-", "force_destroy": false } }, "aws_s3_bucket_cors_configuration": { "Bucket_CorsConfiguration-1357ca3a_A4CCA40A": { "bucket": "${aws_s3_bucket.Bucket.id}", "cors_rule": [{ "allowed_headers": ["*"], "allowed_methods": ["GET","POST","PUT","DELETE","HEAD"], "allowed_origins": ["*"], "expose_headers": [], "max_age_seconds": 0 }] }, "MyClosure_Bucket_CorsConfiguration-e8fb640c_DE3E7CF4": { ... } } } }可观察到的实现事实:
- 资源路径遵循
root/Default/Default/<作用域>/Bucket/Default的命名层级:第一个 bucket 直接挂在根下(id 为Bucket),第二个挂在MyClosure节点下(id 为MyClosure_Bucket_874B5056,其中874B5056是编译器根据作用域路径生成的哈希后缀); bucket_prefix: "bucket-c88fdc5f-"表示 S3 桶名采用"前缀+哈希"的生成方式,force_destroy: false是 SDK 默认值;- 每个 bucket 默认附带一个 CORS 配置资源,允许全部方法(GET/POST/PUT/DELETE/HEAD)、任意来源与任意头——这是
cloud.Bucket在 tf-aws 实现中的默认行为,可在 packages/@winglang/sdk/src/shared-aws/bucket.ts 中进一步核对。
作为对比,lift_via_closure_explicit变体(lift_via_closure_explicit.test.w_compile_tf-aws.md)中类字段是cloud.Queue,其main.tf.json合成的则是aws_sqs_queue:
"aws_sqs_queue": { "MyClosure_Queue_7DFF9F76": { "message_retention_seconds": 3600, "name": "Queue-c832d7dc", "visibility_timeout_seconds": 30 } }message_retention_seconds: 3600、visibility_timeout_seconds: 30都是cloud.Queue的默认参数,且注意该场景只有一个队列资源——因为lift_via_closure_explicit.test.w(tests/valid/lift_via_closure_explicit.test.w)没有模块级的bucket2这类额外资源,整个程序只有类实例里创建的一个Queue。这组对照实验清晰地展示了"资源数量完全由 preflight 层的构造调用决定,而非由 inflight 引用次数决定"。
七、底层原理:SDK 侧的 lift 机制实现
快照中的_liftMap、_liftedState、liftObject都不是编译器临时产物,而是 SDK 定义好的契约。核心实现位于 packages/@winglang/sdk/src/core/lifting.ts:
7.1 类型契约
LiftMap定义为Record<string, Array<[any, Array<string>]>>(操作名 → 对象与操作列表),由 packages/@winglang/sdk/src/std/resource.ts 的IHostedLiftable接口声明。宿主(inflight host)实现onLift钩子,编译器和 SDK 在合成阶段对每个被 lift 的对象恰好调用一次。
7.2 collectLifts:把矩阵展开为依赖图
collectLifts(initialObj, initialOps)(lifting.ts)维护一个"已探索集合"和一个"待探索队列":
- 从
[initialObj, initialOps]出发,对每个对象检查其_liftMap(对象)或_liftTypeMap(类)是否存在; - 对请求的每个操作(加上隐式的
$inflight_init),把_liftMap[op]中的依赖[depObj, depOps]推入队列继续展开; - 若请求的操作在矩阵中不存在,则抛出错误——例如
Resource ${obj.node.path} does not support inflight operation ${op}; - 普通对象(无
_liftMap)如果是数组、Set、Map 或普通对象,则递归展开其元素;若元素是$Closure前缀的 inflight 闭包对象,则隐式附加handle操作。
这正是 5.3 节传递性 lift 得以实现的运行时机制:$Closure3的handle请求了fn2的handle,fn2._liftMap["handle"]又指向[this, ["putFile"]],于是this.bucket的put权限会沿着依赖图被收集,最终统一授予 inflight host。
7.3 Lifting.lift:统一执行授权
Lifting.lift(obj, host, ops)(lifting.ts)先调用collectLifts得到全部需 lift 的对象,再为每个对象调用一次onLift(对象)或onLiftType(类)。若对象带有 token resolver,则调用tokens.onLiftValue(host, liftedObj);若既不是资源也无onLift,说明它是基本类型,无需任何授权。最后把WING_TARGET环境变量注入宿主。
7.4 liftObject:对象的序列化规则
liftObject(obj)(lifting.ts)决定 preflight 对象在 inflight client 工厂参数中如何被代码化:
null/undefined直接JSON.stringify;- 带 token resolver 的对象走
tokenResolver.lift(obj)(如资源引用、token 值); - 带
_toInflightType的类型调用其静态方法生成require(...)表达式; - 字符串/布尔/数字直接序列化;数组、Set、Map 递归展开为对应 JS 结构;
- 资源(有
_toInflight方法)调用obj._toInflight(),其内部通过InflightClient.forV2(packages/@winglang/sdk/src/core/inflight.ts)生成"异步加载 client 类 →new klass({...liftedFields})→ 调用$inflight_init"的代码片段; - 普通对象按结构体逐字段序列化;无法处理时抛出
Unable to lift object of type ...。
此外,Resource._preSynthesize(resource.ts)会在合成前把_liftMap中的依赖转换为资源间的连接(connection)关系,供平台层(如 tf-aws)据此生成 IAM 权限,从而兑现"最小权限"目标。
八、运行与验证:sim 目标下的测试结果
除了编译快照,hangar 还固化了该测试在sim 目标下的运行结果:lift_via_closure.test.w_test_sim.md:
[INFO] call non-synthetic closure as a function | handle called [INFO] call non-synthetic closure as a function | putFile called pass ─ lift_via_closure.test.wsim » root/Default/test:call non-synthetic closure as a function pass ─ lift_via_closure.test.wsim » root/Default/test:call synthetic closure class as a function Tests 2 passed (2) Snapshots 1 skipped Test Files 1 passed (1) Duration <DURATION>从运行日志可以得到两个直接证据:
- 两个测试全部通过,说明合成闭包(
fn())和类闭包(fn2())在 sim 环境下都能被当作函数调用; - 日志中
handle called、putFile called的顺序出现在第二个测试下,证明fn2()触发了handle → putFile → this.bucket.put("hello","world")的完整调用链,且三个assert(fn2.bucket.get("hello") == "world"、fn2.listFiles().length == 1、bucket2.get("b2") == "world")全部通过——传递性 lift 在运行时真实可用。
对照实验 lift_via_closure_explicit.test.w_test_sim.md 同样只有一个pass ─ lift_via_closure_explicit.test.wsim » root/Default/test:test,其 inflight clientinflight.MyClosure-1.cjs的模块工厂形参为空(function({ })),只有$this_q通过构造参数注入——因为该程序中类的handle只访问了实例字段this.q,没有捕获任何模块级变量。这与主用例形成了完美的对照,直观展示了"哪些对象走捕获列表、哪些走实例状态"的划分规则。
九、如何在当前仓库复现与扩展验证
如果你希望亲自复现以上编译产物,可以按以下方式操作(仓库只读,仅运行与查看):
- 运行测试用例:仓库的 hangar 测试套件(tools/hangar)会以
tests/valid/下的.w文件为语料,对sim与tf-aws等目标执行编译/运行并对比快照; - 对比快照:编译产物应稳定匹配 tools/hangar/snapshots/test_corpus/valid/ 目录下以
lift_via_closure开头的四个快照(compile_tf-aws与test_sim各两个); - 自行观察 lift 矩阵:在
preflight.cjs中搜索_liftMap,即可看到每个 inflight 方法的依赖声明;在inflight.*.cjs中查看模块工厂形参,即捕获列表; - 修改验证:如果你在本地有可写的 wing 环境,可以给
MyClosure增加新的 inflight 方法或模块级变量,重新编译后对比_liftMap与捕获列表如何随之变化——这能最直观地理解 lift 的自动分析规则。
十、总结
通过lift_via_closure.test.w在tf-aws目标上的编译快照,本文完整还原了 Wing 闭包 lift 机制的落地产物:
- 合成闭包(
inflight () => {...}字面量)被编译为隐藏的AutoIdResource,其捕获的 preflight 对象经liftObject序列化后作为工厂参数注入 inflight client; - 类闭包(带 inflight 方法的类实例)可直接调用,其实例字段通过
_liftedState()提升为 client 构造参数,模块级变量仍走捕获列表; - 传递性 lift由编译器在
_liftMap中显式声明(如fn2.bucket),由 SDK 的collectLifts在运行时展开为完整依赖图,并最终转化为宿主(如 AWS Lambda)的最小权限配置; main.tf.json只反映 preflight 层的资源构造(本用例中两个 S3 桶及默认 CORS 配置),inflight 引用次数不影响资源数量;- hangar 快照(
compile_tf-aws与test_sim双目标)为这套行为提供了可回归验证的"黄金标准"。
理解这份快照,等于读懂了 Wing 编译器为每个 inflight 闭包生成的三件套——client 工厂、lift 矩阵、权限声明——这也是深入 Wing SDK、平台插件乃至自定义资源onLift实现的基础。
延伸阅读
- 测试源码:tests/valid/lift_via_closure.test.w 与 tests/valid/lift_via_closure_explicit.test.w
- 编译快照:lift_via_closure.test.w_compile_tf-aws.md、lift_via_closure.test.w_test_sim.md
- SDK 实现:packages/@winglang/sdk/src/core/lifting.ts、packages/@winglang/sdk/src/core/inflight.ts、packages/@winglang/sdk/src/std/resource.ts
- 概念文档:docs/docs/02-concepts/01-preflight-and-inflight.md、docs/by-example/16-closures.md
- 设计 RFC:docs/contributing/999-rfcs/2024-03-14-explicit-lift-qualification.md
- 编程语言
- 编译器
- 云原生
- 语言运行时
【免费下载链接】wing
A programming language for the cloud ☁️ A unified programming model, combining infrastructure and runtime code into one language ⚡
相关推荐
Wing tf-aws 编译快照详解:从 captures.test.w 看 inflight 闭包捕获与 Lift 权限生成机制
Wing tf aws 编译快照详解:从 captures.test.w 看 inflight 闭包捕获与 Lift 权限生成机制 本文以 Wing 仓库中一份
编程语言编译器云原生语言运行时Wing 语言 inflight 闭包集合的 Lift 机制解析:从测试快照看 tf-aws 权限生成
Wing 语言 inflight 闭包集合的 Lift 机制解析:从测试快照看 tf aws 权限生成 本指南以 Wing 仓库中 lift_inflight_
编程语言编译器云原生语言运行时Wing 语言 inflight 闭包返回对象的 lift 限定:从 issue6501 回归测试看编译器限定机制
Wing 语言 inflight 闭包返回对象的 lift 限定:从 issue6501 回归测试看编译器限定机制 导读 本文以 Wing 仓库中 lift_i
编程语言编译器云原生语言运行时
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考