改变世界的编程语言MoonBit:项目文件详解

大家好,我是 MoonBit 使用者,也是 MoonBit 布道师,我的个人网站是 https://chensuiyi.me
这是我的 《改变世界的编程语言MoonBit》 系列文章,将自己学习和理解 MoonBit 的过程分享给大家,希望能带来参考和帮助。
全部文章可以前往 MoonBit 开发网 https://moonbit.edgeone.apphttps://moonbit.pages.dev 查看,我坚信,MoonBit 将会改变世界。


上一篇文章 👉改变世界的编程语言 MoonBit:背景知识速览

很多编程语言入门教程,一开始都会教你这个编程语言的语法细节,我觉得这会让我们过早地进入细节而不知全貌。

正所谓一叶障目,不见泰山。如果一开始就林中行走,很难对这门语言产生一个更直观,更整体的印象,我们要登高望远,要横看成岭侧成峰,要远近高低各不同。

所以本文呢,来讲一讲,MoonBit的目录架构

语言文件

MoonBit 语言的专属语言扩展名是 .mbt,可能有人会疑惑为什么不是 .mb?这里我没有找到官方的相关说明,根据我的猜测,.mb 这种二字目扩展名基本已经被很多软件或项目使用了,所以把 MoonBiT 中的 3 个大写字母提取出来作为扩展名,可以有效地防止扩展名歧义和冲突。

测试文件

测试 是保证一个项目,文件,功能,代码的正确性,可用性,维护性的重要环节,在 MoonBit 中,专门为 测试 系统进行了 人性化 的设计。

mbt 复制代码
test "test_name" {
  assert_eq(1 + 1, 2)
  assert_eq(2 + 2, 4)
  inspect([1, 2, 3], content="[1, 2, 3]")
}

除了可以在 .mbt 文件中写 测试块 之外,还提供了 黑盒测试白盒测试

只能访问包中公开成员的测试称为 黑盒测试,能够访问包中所有成员的测试称为 白盒测试,二者都提供了单独的文件来编写和管理测试用例。

黑盒测试的文件扩展名以 _test.mbt 结尾,白盒测试的文件扩展名以 _wbtest.mbt 结尾。

包管理

不管你是前端还是后端,是 JavaScript、Java、Go、Rust 还是 PHP 或 Python,一个现代化的语言,包管理 功能是基础的,也是必备的。

以下是编程语言的包管理机制:

  • JavaScript :npm / yarn / pnpm → package.json
  • Java :Maven / Gradle → pom.xml
  • Go :Go Modules → go.mod
  • Rust :Cargo → Cargo.toml
  • Python :pip / pipenv / poetry → requirements.txt
  • PHP :Composer → composer.json

所以 MoonBit 的包管理是什么呢?那就是 moonmoon.mod.jsonmoon.pkg.json

与 JavaScript 的 npm 一样,moon 不仅承载了包管理的功能,还包括了发布,安装,管理,编译,运行,查看等一系列功能。

模块

一个 项目 对应一个 模块,一个 模块 对应一个 moon.mod.json 文件。

moon.mod.json 文件位于项目的根目录,可以看成是现代前端开发中的 package.json 文件。

一个模块是由 1 个或多个 组成的,每个 moon.pkg.json 文件进行标识和定义。

项目结构

mbt 复制代码
my_project
├── Agents.md
├── cmd
│   └── main
│       ├── main.mbt
│       └── moon.pkg.json
├── LICENSE
├── moon.mod.json
├── moon.pkg.json
├── my_project_test.mbt
├── my_project.mbt
├── README.mbt.md
└── README.md -> README.mbt.md

MoonBit 的项目组织方式与其他语言稍有不同,如上,是通过 moon new 创建的一个新项目,常见的 LICENSEREADME.md 自不必多说,分别是 许可协议项目说明书

README.mbt.md 则是 MoonBit 独有的文件,可以理解为 可编程的说明书,也就是说在 README.mbt.md 文件中写的 MoonBit 代码,与在 .mbt 文件中写代码是没有区别的,照样可以做到编译器的语法校验,提示,修复等。

那么 my_project.mbtmy_project_test.mbt 呢,则是根据项目名称 my_project 默认创建的 同名 语言文件。

模块配置文件 moon.mod.json 的内容如下,chensiuyi 是我们的用户名,my_project 是项目 (模块) 名,用这 2 个名称,可以唯一标识一个项目或模块。

json 复制代码
{
    "name": "chensuiyi/my_project",
    "version": "0.1.0",
    "readme": "README.md",
    "repository": "",
    "license": "Apache-2.0",
    "keywords": [],
    "description": ""
}

所以,我们在说到 的时候,一般是要带上 模块前缀 的,比如根目录下的 moon.pkg.json 则是 chensuiyi/my_project 包。

cmd/main 目录下的 moon.pkg.json,则是 chensuiyi/my_project/cmd/main 包。

所以以上项目一共有 2 个 ,分别是 chensuiyi/my_project 包和 chensuiyi/my_project/cmd/main 包。

chensuiyi/my_project/cmd/main 包是我们的主包,其 moon.pkg.json 文件内容如下:

json 复制代码
{
    "is-main": true,
    "import": [
        {
            "path": "chensuiyi/my_project",
            "alias": "lib"
        }
    ]
}

主包用 is-main 字段为 true 来标记,表示这个包是 moon run 指令的入口,同时也是 moon build 的入口,一个项目可以有 0个多个 主包。

import 则是包与包之间的互相依赖,如上配置,主包 chensuiyi/my_project/cmd/main 依赖了 chensuiyi/my_project 包,并为其设置别名为 lib

凡是有 moon.pkg.json 文件的目录都是 ,而根目录下的 moon.pkg.json 文件则是一个空文件,默认内容只有一个大括号 {} (更多配置后文详解),表示是一个普通包。

项目架构的哲学

mbt 复制代码
my_project
├── Agents.md
├── cmd
│   └── main1
│       ├── main.mbt
│       └── moon.pkg.json
│   └── main2
│       ├── main.mbt
│       └── moon.pkg.json
├── math
│   ├── plus.mbt
│   └── moon.pkg.json
├── LICENSE
├── moon.mod.json
├── moon.pkg.json
├── my_project_test.mbt
├── my_project.mbt
├── README.mbt.md
└── README.md -> README.mbt.md

按照我的个人的理解来说,本文的 项目结构 部分还不足以说明 MoonBit 的架构哲学,所以我把 项目结构 进行了如上扩展。

那么先问个问题,以上有几个 ?答案是 4个,很简单,有几个 moon.pkg.json 就有几个 ,就是如此简单。

根目录下的 moon.pkg.jsoncmdmath 目录下的 moon.pkg.json 没有区别,就像是一个班级的学生,大家都是平等的

is-main 配置为 truefalse 则表明了这个学生的是否有职务,为 true 则在普通包的基础上,有了 主包入口职务

所以当我们执行 moon build --target all 命令的时候,就会生成上图中的 jsnative(exe)wasmwasm-gc 4 种编译结果 (llvm目前还不稳定,只在nightly版本下生成),每个编译结果都有 main1main2 两个文件,与我们上面的配置一致。

如果你写过 go 语言,会发现在 go 约定成俗的规范中,cmd 目录就是应用程序的主入口目录,也是用于生成二进制的目录,所以写过 go 的小伙伴对这个 哲学 应该不会陌生。

内部包

mbt 复制代码
my_project
├── Agents.md
├── cmd
│   └── main1
│       └── internal
│           └── math
│               ├── minus.mbt
│               └── moon.pkg.json
│       ├── main.mbt
│       └── moon.pkg.json
│   └── main2
│       ├── main.mbt
│       └── moon.pkg.json
├── math
│   ├── plus.mbt
│   └── moon.pkg.json
├── LICENSE
├── moon.mod.json
├── moon.pkg.json
├── my_project_test.mbt
├── my_project.mbt
├── README.mbt.md
└── README.md -> README.mbt.md

如果你想创建一个包,但是只能被 main1 包使用,那可以在 main1 目录下创建一个 internal 目录,那么这个目录下的包就只能被 main1 及其子目录使用。

虚拟包

虚拟包是一个实验性功能,可能存在错误和未定义的行为。

json 复制代码
{
    "virtual": {
        "has-default": true
    }
}

moon.pkg.json 文件中,有定义 virtual 字段的,就是 虚拟包

顾名思义,虚拟包就是对 实现的定义,而不是 具体的实现,它们可以在构建时被特定的实现替换。

目前,虚拟包只能包含普通函数。虚拟包在保持代码不变的情况下,可以在不同的实现之间进行切换。

发布包

MoonBit 的中文名称叫做 月兔,每个模块称之为 月饼,放月饼的仓库就是 https://mooncakes.io

所有人都可以发布自己的 月饼 到仓库中,被其他人依赖并使用。

结尾

这就是 MoonBit 目录,文件 的架构 哲学,带大家飞到天上总览全局,有一个大概的轮廓和印象。

下一篇 改变世界的编程语言MoonBit:搞懂配置文件,我们不见不散。

相关推荐
恋猫de小郭42 分钟前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
牛奔2 小时前
Go 如何避免频繁抢占?
开发语言·后端·golang
想用offer打牌7 小时前
MCP (Model Context Protocol) 技术理解 - 第二篇
后端·aigc·mcp
崔庆才丨静觅7 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60618 小时前
完成前端时间处理的另一块版图
前端·github·web components
KYGALYX8 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅8 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
爬山算法9 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate