[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f70K8iKvZbmJ3apVpAX5tdRuI1rYCuHT4SZ0bp8_OW7g":3},{"item":4,"related":48},{"id":5,"type":6,"title":7,"slug":8,"summary":9,"body":10,"coverUrl":11,"productScreenshots":12,"productLinks":13,"authorName":14,"authorUrl":15,"authorSubject":16,"category":17,"tags":22,"sourceLabel":39,"sourceName":40,"sourceUrl":41,"status":42,"seoTitle":7,"seoDescription":9,"canonicalUrl":39,"isFeatured":43,"sno":44,"sortOrder":45,"publishedAt":46,"updatedAt":47,"createdAt":47},"59ab3e13-b2e4-4da8-a952-52e1a8b31501","article","Gradual Typing：动态类型和静态类型怎样和平共处？","gradual-typing-static-dynamic-explained","Gradual Typing 允许一个项目逐步添加类型：静态区域获得更强检查，动态区域保留快速试验能力，跨越边界时由运行时检查兜底。本文解释类型迁移、动态边界和 AI 原型演进中的实际取舍。","静态类型擅长尽早发现错误，动态类型则适合快速试验和处理变化频繁的代码。Gradual Typing，中文常译为“渐进式类型”或“渐进类型”，试图让两种风格出现在同一个程序里：有类型标注的部分获得更强检查，没有标注的部分仍然保留动态灵活性。\n\n## 为什么需要“渐进”\n\n一个长期维护的项目很少能一次性完成全面类型化。团队可能先给核心数据结构加类型，再逐步覆盖接口、工具函数和边缘模块。如果类型系统只接受“全有”或“全无”，迁移成本会很高。\n\n渐进式类型的核心是允许程序存在一个较宽的未知类型边界。静态部分和动态部分交互时，系统会插入运行时检查，确保实际值符合静态代码期待的形状。如果检查失败，错误会在边界处暴露，而不是悄悄传播到更深处。\n\n## 它不是“类型随便写”\n\n渐进类型仍然需要定义静态类型、动态类型和它们之间的转换语义。一个重要问题是：当类型信息不完整时，检查应该发生在什么时候？错误应该归因到调用者、被调用者还是转换边界？这些问题决定了语言的安全性和调试体验。\n\nTypeScript、Python 的类型标注以及一些现代语言的动态边界，都可以帮助普通开发者感受这种思想，但不同工具的实现和保证并不完全相同。类型检查通过，也不等于外部数据已经可信；网络响应、用户输入和数据库记录仍然需要运行时验证。\n\n## 对 AI 生成代码有什么帮助\n\nAI 经常先生成一个能跑的原型，再逐步补齐类型。渐进式类型提供了一条现实的演进路线：先在高风险接口、共享数据结构和核心算法上增加约束，再处理低风险胶水代码。\n\n真正有价值的是边界意识。每一个动态区域都应该知道自己把哪些责任交给运行时，每一个静态区域都应该知道自己依赖了哪些输入前提。否则“渐进”很容易变成永久的模糊。\n\n## 读者应该记住\n\nGradual Typing 不是在静态和动态之间二选一，而是把两者连接起来，并在边界插入检查。它让类型系统更适合渐进迁移，但也要求团队认真管理动态边界。\n\n资料：[Siek & Taha：Gradual Typing for Functional Languages](https:\u002F\u002Fjsiek.github.io\u002Fhome\u002Fsiek06gradual.pdf)","\u002Fuploads\u002F2026-09-20\u002Fedecee61-6a61-4c1a-b3d6-14b2da579b32.jpg",[],[],"Foundit","https:\u002F\u002Ffoundit.cn","foundit-ai-editorial",{"id":18,"name":19,"slug":20,"description":21},"6179d3b6-dc34-4483-9ded-3cd9f1b37a47","科普","abbreviation","介绍各领域新兴概念",[23,27,31,35],{"id":24,"name":25,"slug":26},"144abe77-0dc6-4f66-a176-20bddb1c0bfa","编程","coding",{"id":28,"name":29,"slug":30},"a202d639-99a6-488a-a712-4d4c6ffd7e15","开发","dev",{"id":32,"name":33,"slug":34},"7c76bfc2-f80f-4ee0-a95d-27bd8708b434","技术","slug",{"id":36,"name":37,"slug":38},"68cedb55-2cac-412f-8f81-fda8c7d686dd","思考","thought",null,"Siek & Taha：Gradual Typing for Functional Languages","https:\u002F\u002Fjsiek.github.io\u002Fhome\u002Fsiek06gradual.pdf","published",false,60,0,"2026-09-20T00:00:00.000Z","2026-09-20T03:57:55.525Z",[49,58,66],{"id":50,"type":6,"title":51,"slug":52,"summary":53,"coverUrl":54,"authorName":14,"sno":55,"publishedAt":56,"createdAt":57},"3ee91529-a5cf-40b1-ab91-69df08e489ea","Hazard Pointers：无锁数据结构删除节点后，谁来保证它还没被读到？","hazard-pointers-memory-reclamation","Hazard Pointers 让线程在访问节点前公开保护标记，删除者延迟回收并扫描这些标记，从而避免悬空指针与部分 ABA 风险。","\u002Fuploads\u002F2026-09-26\u002Ffd52a815-7e19-4622-9182-6ca2df8e8144.jpg",42,"2026-09-27T00:00:00.000Z","2026-09-26T16:25:44.416Z",{"id":59,"type":6,"title":60,"slug":61,"summary":62,"coverUrl":63,"authorName":14,"sno":64,"publishedAt":56,"createdAt":65},"bd1746b8-937b-48cf-ae66-0116d7062e67","Epoch Reclamation：并发程序为什么要等“这一代线程”都走完再释放内存？","epoch-based-memory-reclamation","基于纪元的回收把退休对象标记到某一代，等所有可能看见它的参与者跨过该纪元后再批量释放，适合高并发无锁结构。","\u002Fuploads\u002F2026-09-26\u002F2eb6fe27-ea9d-440a-877f-965f5158edb4.jpg",43,"2026-09-26T16:25:47.831Z",{"id":67,"type":6,"title":68,"slug":69,"summary":70,"coverUrl":71,"authorName":14,"sno":72,"publishedAt":73,"createdAt":74},"4ce57934-2b23-41a1-800e-bb2d8ab36684","Wasm Component Model：不同语言写的模块怎样用同一套接口协作？","wasm-component-model-wit-interfaces","WebAssembly Component Model 用有类型的接口描述组件如何交换数据与调用功能，WIT 则帮助表达这些接口。本文用模块化电器说明跨语言组合的意义，也指出它不代表程序脱离运行时就能在任何环境原样运行。","\u002Fuploads\u002F2026-10-17\u002F0eb1c88d-dc1f-486d-8194-54f72dd215ec.jpg",45,"2026-10-17T00:00:00.000Z","2026-10-17T03:08:52.474Z"]