Skip to Content

资源作用域(Using)

using 将资源的生命周期限定在块作用域内:进入时拿着资源,离开块时自动调用 Dispose。文件句柄、数据库连接、事务这类文件句柄、数据库连接这类需要显式释放的资源都适用。

资源的契约:Disposable

using 的宿主类型必须实现 Disposable 协议,也就是提供一个无参的 Dispose 方法。协议经 import System.Disposable; 引入:

import System.Disposable; class FileHandle impl Disposable { public var name: string; init(n: string) { name = n; print("打开", name); } public func Dispose() { print("关闭", name); } }

三种形态

using val r = new Resource(); { } // 声明并绑定(无分号,块紧随) using name = expr { } // 资源绑定 using expr { } // 表达式资源

声明形的绑定在块内可见,块外不存在。构造实参直接写进 new,不要用对象初始化器:初始化器的 { 会和 using 的主体块混淆。

嵌套与释放顺序

using 块结束时立刻 Dispose,嵌套时按进入的逆序释放,后开的先关:

using val outer = new FileHandle("数据库") { using val inner = new FileHandle("事务") { print("使用", outer.name, "和", inner.name); } print("事务已关,数据库还开着"); } print("全部关闭");
打开 数据库 打开 事务 使用 数据库 和 事务 关闭 事务 事务已关,数据库还开着 关闭 数据库 全部关闭

内层块一结束事务就关掉,数据库句柄留到外层块结束。这个顺序和 defer 的后进先出同构。

表达式形

不需要给资源起名字时用表达式形,块内拿不到引用,纯粹为了「进出配对」:

using new FileHandle("临时") { print("一次性资源"); } print("块外继续");
打开 临时 一次性资源 关闭 临时 块外继续

注意

  • using 的主体必须是块,using r; 单独一句是语法错误。
  • Dispose 是普通方法,实现了 Disposable 的类型也可以手工调用,但用了 using 就不必手工管。
  • 析构器 deinit 只在 using 退出时补调(沿基类逆序),普通块退出不触发,脚本版语言不对析构时机做承诺。
  • 协议本身也能当资源类型(using val p: P = new R()),Dispose 经协议槽分派到具体类型,前提是协议声明链里带着 Dispose 签名。
最后更新于 2026年10月10日