改变世界的编程语言 MoonBit
大家好,我是农村程序员,独立开发者,前端之虎陈随易,我的个人网站是
https://chensuiyi.me
这是我的《改变世界的编程语言MoonBit》
系列文章,将自己学习和理解 MoonBit 的过程分享给大家,希望能带来参考和帮助。
全部文章可以前往 MoonBit 开发网https://moonbit.edgeone.app
或https://moonbit.pages.dev
查看,我坚信,MoonBit 将会改变世界。
往期文章
学习理念
学习一个编程语言,我不喜欢一来就上手语法细节,什么变量定义方式,类型有哪几种,函数的定义方式等等。
我更喜欢剥洋葱一样,先从最外层开始,逐渐层层递进,最后才得到我们真正食用的部分。
而洋葱的外皮部分,正如我们本文和本系列的往期文章一样,是我们了解一个编程语言的味道,性格,脾气,特点的重要组成部分。
MoonBit 配置类型
- 一个是
模块配置
,文件名称是moon.mod.json
- 一个是
包配置
,文件名称是moon.pkg.json
按照 MoonBit 的约定俗称来说,一个目录下面有一个moon.mod.json
文件,那么这个目录就是一个模块
,本文或本视频,主要分享模块
的配置和理解。

文件名:moon.mod.json
json
{
"name": "chensuiyi/example1", // 模块名称
"description": "这是模块的描述", // 模块描述
"version": "0.1.0", // 模块版本
"keywords": ["example", "test"], // 模块关键字
"source": ".", // 源码目录
"license": "MIT", // 许可协议
"readme": "README.md", // 指定 readme.md 文件的路径
"repository": "https://github.com/chenbimo/befly", // 源码仓库地址
"exclude": ["build"], // 发布时要排除的内容
"include": ["build/assets"], // 发布是要包含的内容
"preferred-target": "js", // 首选编译目标,可以减少输入 --target 参数
// 模块依赖,类似 pageage.json 的 dependencies
"deps": {
"moonbitlang/x": "0.4.6"
},
// 二进制依赖
"bin-deps": {
"moonbitlang/yacc": "0.6.14",
"username/flash": {
"path": "../author1.in",
"bin_pkg": ["main-js", "main-wasm"]
}
},
"scripts": {
"postadd": "python3 build.py"
},
"warn-list": "-2-4+31",
"alert-list": "-test_import_all+deprecated-warn",
"--moonbit-unstable-prebuild": "<path/to/build-script>"
}
deps 依赖说明
deps
就像是你做菜需要的食材清单。如果你要做一道红烧肉,你需要猪肉、酱油、糖等食材。同样,如果你的项目要实现某些功能,可能需要依赖其他开发者已经写好的模块。
添加依赖 :使用命令 moon add moonbitlang/async
就能把这个模块加入到你的项目中。
移除依赖 :如果不需要了,使用 moon remove moonbitlang/async
移除即可。
在代码中使用:
第一步:在包配置中导入
在 moon.pkg.json
文件中配置 import
字段:
json
{
"import": ["moonbitlang/async"]
}
第二步:在代码中调用
使用 @包名
的形式调用依赖中的功能:
ini
let result = @async.run(task)
典型应用场景:
场景一:开发一个 Web 服务,需要同时处理多个用户请求,避免单个请求阻塞整个服务。
- 添加依赖:
moon add moonbitlang/async
- 使用异步任务调度功能处理并发请求
- 提升服务器的响应能力和吞吐量
场景二:项目需要使用高级数据结构(如优先队列、红黑树等),但不想自己实现。
- 添加依赖:
moon add moonbitlang/x
(MoonBit 扩展库) - 直接使用现成的数据结构和算法
- 节省开发时间,提高代码质量
场景三:需要解析和生成 JSON 数据,用于 API 接口开发。
- 添加 JSON 处理相关的依赖
- 使用库提供的序列化和反序列化功能
- 避免手动解析 JSON 字符串的麻烦
bin-deps 依赖说明
如果说 deps
是做菜的食材,那么 bin-deps
就是厨房里的工具,比如菜刀、砧板、炒锅等。这些工具不是最终菜品的一部分,但在制作过程中必不可少。
在编程中,bin-deps
通常是一些构建工具 、代码生成器 或预处理器,它们帮助我们生成代码、处理文件,但不会出现在最终的程序中。
典型应用场景:
- 代码生成 :比如
yacc
工具可以根据语法定义文件自动生成解析器代码 - 文件转换:将某种格式的文件转换成另一种格式
- 预处理:在正式编译前对代码进行某些处理
使用方式:
安装工具:
- 添加:
moon add --bin moonbitlang/yacc
- 移除:
moon remove moonbitlang/yacc
使用工具的三种方式:
方式一:包配置中的 pre-build(推荐)
在 moon.pkg.json
中配置 pre-build
,每次构建前自动执行,这是最稳定的方式。
适用场景:需要在每次编译前自动生成代码的情况。
方式二:命令行直接调用
通过命令 moon run moonbitlang/yacc
手动执行工具。
适用场景:偶尔需要执行一次,或者用于测试工具是否正常工作。
方式三:模块级别脚本(实验性)
在 moon.mod.json
中配置 --moonbit-unstable-prebuild
,目前还不稳定。
适用场景:模块级别的预构建任务,但因为不稳定,建议谨慎使用。
实际场景举例:
假设你要做一个计算器程序,需要先定义数学表达式的语法规则(比如 2 + 3 * 4
该怎么计算)。
你可以:
- 在
grammar.y
文件中定义语法规则 - 使用
yacc
工具自动生成解析这些规则的代码 - 将生成的代码加入到你的项目中
这样就不需要手动编写复杂的解析逻辑了。
deps 与 bin-deps 的区别
对比项 | deps | bin-deps |
---|---|---|
作用 | 项目运行需要的功能模块 | 构建过程需要的工具 |
能否导入 | ✅ 可以在代码中导入使用 | ❌ 不能导入,只能作为工具使用 |
打包 | ✅ 会打包到最终程序中 | ❌ 不会打包,只在开发时使用 |
类比 | 做菜的食材 | 厨房的工具 |
scripts 配置说明
scripts
就像是自动化的小助手,可以在特定时间点自动帮你执行一些任务,就像你设置的闹钟,到点了就会自动响。
目前支持的钩子:postadd
- 触发时机:当模块被添加为依赖后自动执行。
- 通俗理解 :当别人使用
moon add
命令把你的模块添加到他们的项目时,这个脚本就会自动运行。
典型使用场景:
- 安装额外依赖:可能需要安装一些系统工具或其他依赖
- 生成配置文件:根据模板自动生成项目所需的配置文件
- 初始化项目结构:创建必要的目录和文件
- 执行构建脚本:编译某些资源文件或生成代码
实际场景举例:
场景一:假设你开发了一个前端组件库,当别人安装你的组件库时,需要自动安装 npm 依赖并构建样式文件
- 执行
npm install
安装依赖 - 执行构建脚本生成 CSS 文件
场景二:你的模块需要一个配置文件,可以让脚本自动从模板生成配置文件,省去用户手动配置的麻烦
场景三:检查用户的系统环境是否满足要求,比如检查 Python 版本、Node.js 版本等
与 pre-build 的区别:
对比项 | scripts (postadd) | pre-build |
---|---|---|
配置位置 | moon.mod.json(模块配置) | moon.pkg.json(包配置) |
触发时机 | 模块被添加时 | 每次构建前 |
执行频率 | 只执行一次(安装时) | 每次构建都执行 |
主要用途 | 初始化、安装依赖 | 代码生成、预处理 |
类比 | 新房装修(只做一次) | 每天做饭前的准备 |
scripts
配置让你的模块更加智能和自动化,用户在安装你的模块时能够自动完成必要的初始化工作,大大提升使用体验。
warn-list 配置说明
在写代码的时候,编译器(把代码翻译成计算机能懂的语言的工具)会给出各种警告
,就像老师批改作业时用红笔标注的问题。
warn-list
就是用来控制这些警告的开关
,你可以选择哪些警告要显示,哪些要隐藏。
为什么需要控制警告?
开发阶段
在快速开发时,代码可能有很多临时变量、测试代码,编译器会提示一大堆警告。
这时候可以暂时关闭一些不重要的警告,专注于核心功能的实现。
生产阶段
当项目要正式发布时,需要开启所有警告,确保代码质量,避免潜在的问题。
语法规则:
warn-list
使用简单的符号来控制:
- 关闭警告 :用
-
加编号,比如-2
表示关闭 2 号警告 - 开启警告 :用
+
加编号,比如+31
表示开启 31 号警告 - 多个警告 :直接连在一起写,比如
-2-4+31
常见警告类型:
编号 | 警告内容 | 通俗解释 |
---|---|---|
2 | 未使用的变量 | 你定义了一个变量但没有使用它 |
3 | 未使用的类型 | 你定义了一个数据类型但没有使用它 |
31 | 未使用的可选参数 | 函数的某个可选参数一直没被用过 |
32 | 未使用的默认值 | 给参数设置了默认值但从没用到 |
实际应用场景:
场景一:快速验证想法,代码中有很多试验性的变量和函数,这时候可以关闭"未使用变量"的警告,让控制台干净一点
配置:-2(关闭未使用变量警告)
场景二:准备提交代码给团队审查前,开启所有警告,确保代码规范
配置:+31+32(开启未使用可选参数和默认值的警告)
场景三:在模块配置文件中统一设置警告规则,让整个团队保持一致的代码风格。
配置:-2+31(关闭变量警告,开启参数警告)
配置级别:
配置位置 | 影响范围 | 适用场景 |
---|---|---|
moon.mod.json | 整个模块 | 统一整个项目的警告策略 |
moon.pkg.json | 单个包 | 针对特定包的特殊需求 |
优先级:包级别的配置会覆盖模块级别的配置。
注意事项:
⚠️ 不要滥用:关闭警告不是用来掩盖代码问题,而是为了在不同阶段关注不同的重点。就像医生做手术时会专注于关键步骤,但不意味着忽视其他方面。
warn-list
是一个灵活的警告管理工具,让你能够根据项目阶段和需求,合理控制编译器的警告提示,在保证代码质量和提高开发效率之间找到平衡。
alert-list 配置说明
如果说 warn-list
是编译器内置的固定警告
,那么 alert-list
就是开发者自己定义的个性化警告
。
就像公司里有固定的规章制度(warn-list
),同时各个部门还可以根据自己的情况制定特殊规定(alert-list
)。
为什么需要自定义警告?
场景一:你开发了一个函数,后来发现有更好的实现方式,但不能立即删除旧版本(因为别人可能在用)。这时候可以给旧函数添加"废弃警告",提示使用者迁移到新版本
场景二:某些函数如果使用不当会导致错误(比如除法运算,除数不能为 0),可以添加"不安全警告"提醒使用者注意。
场景三:新功能还在测试阶段,可能会改变,添加实验性警告
让使用者知晓。
语法规则:
alert-list
使用名称而非编号来控制:
- 关闭警告 :用
-
加名称,如-deprecated
- 开启警告 :用
+
加名称,如+deprecated
- 多个警告 :直接连在一起,如
-deprecated-unsafe
常见的 Alert 类型:
Alert 名称 | 含义 | 使用场景 |
---|---|---|
deprecated | 已废弃 | 旧版本 API,建议使用新版本 |
unsafe | 不安全 | 可能导致错误的操作 |
experimental | 实验性 | 还在测试的新功能 |
自定义名称 | 自定义 | 根据项目需求定义 |
如何定义 Alert?
在函数、类型等上方用特殊注释 /// @alert
来定义警告:
csharp
格式:/// @alert <类别名称> "<提示消息>"
通俗理解 :就像给函数贴个警告标签
,说明它有什么问题,应该怎么处理。
warn-list 与 alert-list 的对比:
特性 | warn-list | alert-list |
---|---|---|
控制对象 | 编译器内置的警告 | 开发者自定义的警告 |
使用标识 | 数字编号(如 -2 ) |
名称(如 -deprecated ) |
定义方式 | 编译器预设,无法修改 | 使用 @alert 自定义 |
灵活性 | 固定的警告类型 | 可以创建任意警告类型 |
类比 | 交通法规(全国统一) | 小区公约(自己制定) |
配置级别:
配置位置 | 影响范围 | 适用场景 |
---|---|---|
moon.mod.json | 整个模块 | 统一的警告策略 |
moon.pkg.json | 单个包 | 特定包的特殊需求 |
举例:测试代码包可以关闭废弃警告,因为测试旧功能是必要的。
alert-list
让你能够:
- 定义个性化警告:根据项目需求创建自定义警告
- 优雅地废弃 API:给用户充足的迁移时间和清晰的指引
- 标记危险操作:提醒使用者注意可能的风险
- 灵活控制提示:根据开发阶段选择性显示警告
配合 @alert
标记和 alert-list
配置,你可以为项目建立完善的警告体系,提升代码质量和用户体验。