大家好,拜个晚晚年了!
我为了审阅[某个PR](https://github.com/typst-community/wasm-minimal-protocol/pull/65),初步尝试了下MoonBit,不过遇到了很多困难。大部分困难我不确定是否算MoonBit的缺陷,算的话也不确定应该报到哪个 GitHub 仓库,所以就直接在这里反馈了。
注:“新用户在一个帖子中仅能发布 2 个链接”,我就变通处理了。
$MOONBIT_INSTALL_VERSION及其格式不明
[安装 MoonBit CLI Tools](https://www.moonbitlang.com/download/#moonbit-cli-tools) 界面没有介绍如何安装特定版本(而不是最新版)。然而对于时刻在变化的新语言,固定版本通常很必要,特别是在CI上。
我查看[install/unix.sh](https://cli.moonbitlang.cn/install/unix.sh),发现支持环境变量$MOONBIT_INSTALL_VERSION,但没找到是变量应该是什么格式。经过一番调查试验,最终确定它指定的是moonc的版本(而非moon),而且格式需要加hash。例如以下这个版本,应该要指定MOONBIT_INSTALL_VERSION=0.8.2+8cca5f22a。
$ moon version --all
moon 0.1.20260209 (b129ae2 2026-02-09) ~/.moon/bin/moon
moonc v0.8.2+8cca5f22a (2026-02-25) ~/.moon/bin/moonc
moonrun 0.1.20260209 (b129ae2 2026-02-09) ~/.moon/bin/moonrun
moon-pilot 0.0.1-df92511 (2026-02-25) ~/.moon/bin/moon-pilot
文档版本号可能过时
[MoonBit Documentation](https://docs.moonbitlang.com/en/latest/index.html)选择 latest 时,<title>是 MoonBit v0.7.1 documentation,但根据上一节我操作的结果,目前 latest 好像是 0.8.2。这是文档落后呢,还是仅仅<title>标错了?
moon fmt添加的///|缺少解释
对于没有注释的函数,运行moon fmt后会添加///|,如下。
+ ///|
pub fn hi() -> Int {
0
}
我不清楚它和///有什么区别。我在 [MoonBit Language — MoonBit v0.7.1 documentation](https://docs.moonbitlang.com/en/latest/language/index.html) 没有找到任何关于///|的解释。它第一次出现是在介绍 async 时,难道///|和 async 有关?
我询问通用LLM,回复说这是避免 markdown 列表被错误合并成一行,但我也没在文档中找到 line wrap 相关信息,而且多行都用///|的话,会被moon fmt修改:
///| - a
- ///| - b
+ ///|
+ /// - b
pub fn hi() -> Int {
0
}
至今我仍不清楚///|的意义。
moon fmt转换出的moon.pkg不稳定
如果用moon.pkg.json,运行moon fmt会转换为moon.pkg(这让我比较惊讶,但可能设计如此,也还好)。
问题在于,第一次运行时moon.pkg最后没有空行,第二次运行会给加上,正常应该一步到位。
Bytes与FixedArray[Byte]等的关系不明
我在 [Bitstring Pattern — Fundamentals — MoonBit documentation](https://docs.moonbitlang.com/en/latest/language/fundamentals.html#bitstring-pattern) 看到 MoonBit 有多种方式表示字节序列:
BytesView,Bytes,Array[Byte],FixedArray[Byte],ReadOnlyArray[Byte], andArrayView[Byte]
其它几个还相对好理解,但Bytes和FixedArray[Byte]是什么关系呢?通用LLM说前者是后者的别名,但我实测好像二者不能互换,而且内存结构也不同(前者开头有八个字节的零,后者开头有四个字节0xFF和另外四个我不清楚意义的字节)。
此外,如果我定义一个函数,需要读取一串长度任意的字节而无需修改,那么函数的参数应该用哪种?这在文档里似乎没有解释。
我在论坛上看到下面这段解释,但还是很模糊……
[DeepWiki 的分析](https://deepwiki.com/search/bytesfixedarraybyte_90421b28-fe57-4814-a7c4-27b160960db2?mode=fast)也有一定帮助,但仍未解决问题。
blit 函数系列不全
处理字节时,经常需要整块memcpy。根据我的调查,MoonBit把这类函数叫blit_to/blit_from_*。
然而MoonBit有多种方式表示字节序列,并不是每两种方式之间都能blit。我在 [core – mooncakes](https://mooncakes.io/docs/moonbitlang/core/) 只查到了下面几种:
Array::blit_to(..., dst : Array[A], ...)
ArrayView::blit_to(..., dst : Array[A], ...)
FixedArray::blit_from_bytes(..., src : Bytes, ...)
FixedArray::blit_from_bytesview(..., src : BytesView)
FixedArray::blit_from_string(..., str : String, ...)
FFI缺少字节
在 [Foreign Function Interface (FFI)](https://docs.moonbitlang.com/en/latest/language/ffi.html#types) 中,Wasm后端并无任何字节、数组相关的类型,那应该怎样向host传递字节呢?
我们现在的做法是在moon.pkg设置"export-memory-name": "memory",然后通过以下函数把 Bytes 的地址转成Int传出去。
#borrow(bs)
extern "wasm" fn data_ptr(bs : Bytes) -> Int =
#|(func (param i32) (result i32)
#| local.get 0
#| i32.const 8
#| i32.add)
// 以上加八是试验出来的,我没在文档中找到能确认的信息。
Types not mentioned above do not have a stable ABI, so your code should not depend on their representations.
以上 FFI 文档说Bytes的 API 不稳定,那这种做法恐怕过几个版本就可能失效了?有没有更可靠的办法呢?
E4042 解释不实
错误代码 [E4042 — MoonBit documentation](https://docs.moonbitlang.com/en/latest/language/error_codes/E4042.html) 说:
For example, you cannot use
FixedArray[T]andStringin FFI definition on WASM linear backend.
但我实测FixedArray[Byte]可以,而FixedArray[Int]确实不行。
discuss 和 taolun 论坛的关系不明
我查到有 https://discuss.moonbitlang.com/ 和 https://taolun.moonbitlang.com/ 两个论坛。前者主要英文,后者主要中文,而且两论坛似乎相互均未提及。这两个论坛有取代继承关系吗?若是共同运行,建议置顶帖子介绍一下。