改变世界的编程语言 MoonBit
大家好,我是农村程序员,独立开发者,前端之虎陈随易,我的个人网站是
https://chensuiyi.me
这是我的《改变世界的编程语言MoonBit》系列文章,将自己学习和理解 MoonBit 的过程分享给大家,希望能带来参考和帮助。
全部文章可以前往 MoonBit 开发网https://moonbit.edgeone.app或https://moonbit.pages.dev查看,我坚信,MoonBit 将会改变世界。
往期文章
- 改变世界的编程语言 MoonBit:背景知识速览
- 改变世界的编程语言 MoonBit:项目文件详解
- 改变世界的编程语言 MoonBit:配置系统介绍(上)
- 改变世界的编程语言 MoonBit:配置系统介绍(下)
- 改变世界的编程语言 MoonBit:如何用于前端开发
- 改变世界的编程语言 MoonBit:语法基础概述
在上一篇文章中,我们对 MoonBit 的语法基础做了一个概览。今天,我们将深入探讨 MoonBit 中最基础也是最重要的部分------内置数据结构。
数据结构是编程语言的基石,了解它们对于编写高效、正确的代码至关重要。MoonBit 提供了一套丰富且高效的内置数据结构,涵盖了从最基本的布尔值、数字到复杂的数组、映射等。
本文将带你逐一解析这些内置数据结构,并通过详细的代码示例帮助你掌握它们的用法。
本文目录:
- Unit (单元类型)
- Bool (布尔值)
- Numbers (数字类型)
- String (字符串)
- Char (字符)
- Byte & Bytes (字节与字节序列)
- Tuple (元组)
- Ref (可变引用)
- Option & Result (选项与结果)
- Array & FixedArray (数组)
- ArrayView (数组视图)
- Map (哈希映射)
- Set (集合)
- Json (JSON 支持)
- 重载字面量 (Overloaded Literals)
Unit (单元类型)
Unit 是 MoonBit 中一个特殊的类型,它表示"没有有意义的值"。它只有一个值,写作 ()。
如果你熟悉 C/C++ 或 Java,可以将它类比为 void。但不同的是,Unit 在 MoonBit 中是一个真正的类型,可以作为函数的参数、返回值,甚至存储在数据结构中。这使得 MoonBit 的类型系统更加一致和灵活。
应用场景:
- 执行操作但不返回结果的函数(如打印日志、修改全局状态等)
- 作为泛型类型的占位符
- 在函数式编程中表示"无需返回值"的操作
moonbit
fn print_hello() -> Unit {
println("Hello, world!")
}
fn main {
let u : Unit = () // 显式定义 Unit 类型变量
print_hello() // 调用返回 Unit 的函数
// Unit 也可以存储在数组中
let units : Array[Unit] = [(), (), ()]
println(units.length()) // 3
}
与其他语言的对比:
| 语言 | 类似概念 | 是否为真正的类型 |
|---|---|---|
| C/C++ | void |
❌ 不能作为变量类型 |
| Java | void / Void |
Void 可以,但笨重 |
| Rust | () |
✅ 是 |
| MoonBit | Unit / () |
✅ 是 |
Bool (布尔值)
布尔类型 Bool 只有两个值:true (真) 和 false (假)。它是控制流(如 if 语句、while 循环)的基础。
基础用法
moonbit
fn main {
let is_moonbit_fast = true
let is_coding_hard = false
if is_moonbit_fast {
println("MoonBit is fast!")
}
}
逻辑运算符
MoonBit 支持标准的逻辑运算:
| 运算符 | 含义 | 示例 | 结果 |
|---|---|---|---|
&& |
逻辑与 (AND) | true && false |
false |
| ` | ` | 逻辑或 (OR) | |
not() |
逻辑非 (NOT) | not(true) |
false |
moonbit
fn main {
let a = true
let b = false
// 逻辑与:两者都为真才为真
let both = a && b // false
// 逻辑或:至少一个为真就为真
let either = a || b // true
// 逻辑非:取反
let not_a = not(a) // false
// 复合运算
let complex = (a || b) && not(b) // true
println("both: \{both}, either: \{either}, not_a: \{not_a}")
}
短路求值
MoonBit 的 && 和 || 运算符采用短路求值策略:
&&:如果左边为false,则不会计算右边||:如果左边为true,则不会计算右边
moonbit
fn expensive_check() -> Bool {
println("This is an expensive operation!")
true
}
fn main {
let result = false && expensive_check() // 不会执行 expensive_check()
println("Result: \{result}")
}
Numbers (数字)
MoonBit 提供了丰富的数字类型,以满足不同场景下的精度和性能需求。
整数类型
| 类型 | 描述 | 示例 | 值范围 |
|---|---|---|---|
Int |
32 位有符号整数 (默认) | 42 |
-2³¹ ~ 2³¹-1 |
Int64 |
64 位有符号整数 | 1000L |
-2⁶³ ~ 2⁶³-1 |
Int16 |
16 位有符号整数 | (42 : Int16) |
-32768 ~ 32767 |
UInt |
32 位无符号整数 | 14U |
0 ~ 2³²-1 |
UInt64 |
64 位无符号整数 | 14UL |
0 ~ 2⁶⁴-1 |
UInt16 |
16 位无符号整数 | (14 : UInt16) |
0 ~ 65535 |
BigInt |
大整数 (任意精度) | 10000N |
无限制 |
浮点数类型
| 类型 | 描述 | 示例 | 精度 |
|---|---|---|---|
Double |
64 位浮点数 (默认) | 3.14 |
~15-17 位有效数字 |
Float |
32 位浮点数 | (3.14 : Float) |
~6-9 位有效数字 |
数字字面量增强
为了提高代码可读性,MoonBit 允许在数字中使用下划线 _ 分隔,支持多种进制表示。
moonbit
fn main {
// 下划线分隔,增强可读性
let million = 1_000_000
let billion = 1_000_000_000L // Int64
// 二进制 (0b/0B) - 以 0 和 1 表示
let bin = 0b110010 // 50
let flags = 0b1010_1111 // 175
// 八进制 (0o/0O) - 以 0-7 表示
let oct = 0o1234 // 668
let permissions = 0o755 // Unix 文件权限
// 十六进制 (0x/0X) - 以 0-9 和 A-F 表示
let hex = 0xFF // 255
let color = 0xFF_AA_BB // RGB 颜色值
// 科学计数法
let light_speed = 3.0e8 // 3 × 10⁸
let planck = 6.626e-34 // 普朗克常数
}
数学运算
moonbit
fn main {
let a = 10
let b = 3
// 基本运算
let sum = a + b // 13
let diff = a - b // 7
let product = a * b // 30
let quotient = a / b // 3 (整数除法)
let remainder = a % b // 1 (取模)
// 比较运算
let is_equal = a == b // false
let is_greater = a > b // true
let is_less_eq = a <= b // false
println("Sum: \{sum}, Quotient: \{quotient}, Remainder: \{remainder}")
}
类型转换
MoonBit 不会自动进行数字类型转换,需要显式调用转换方法:
moonbit
fn main {
let int_val : Int = 42
let double_val : Double = 3.14
// Int 转 Double
let int_to_double = int_val.to_double() // 42.0
// Double 转 Int (截断小数部分)
let double_to_int = double_val.to_int() // 3
// Int 转 Int64
let int_to_int64 = int_val.to_int64() // 42L
println("int_to_double: \{int_to_double}, double_to_int: \{double_to_int}")
}
String (字符串)
String 是 UTF-16 编码的字符序列。MoonBit 的字符串功能非常强大,支持多行字符串、字符串插值和丰富的操作方法。
基础用法
moonbit
fn main {
let s = "Hello, MoonBit!"
println(s)
// 获取长度
let len = s.length()
println("Length: \{len}") // 15
// 访问单个字符 (返回 Int,表示 UTF-16 码点)
let first_char = s[0]
println(first_char)
}
转义字符
| 转义序列 | 含义 |
|---|---|
\n |
换行 |
\r |
回车 |
\t |
水平制表符 |
\b |
退格 |
\\ |
反斜杠 |
\u5154 |
Unicode 转义 (4 位) |
\u{1F600} |
Unicode 转义 (可变长度) |
moonbit
fn main {
let with_newline = "Line 1\nLine 2"
let with_tab = "Name:\tMoonBit"
let with_unicode = "\u5154\u5b50" // 兔子
let with_emoji = "\u{1F600}" // 😀
println(with_newline)
println(with_tab)
println(with_unicode)
}
多行字符串
使用 #| 可以轻松创建多行字符串,无需手动添加换行符。每行以 #| 开头。
moonbit
fn main {
// 使用 #| 保留原始字符串(不处理转义)
let poem =
#|床前明月光
#|疑是地上霜
#|举头望明月
#|低头思故乡
println(poem)
// 使用 $| 处理转义和插值
let lang = "MoonBit"
let greeting =
$|Hello, \{lang}!
$|Welcome to the future.
println(greeting)
}
字符串插值
使用 \{expression} 语法可以在字符串中嵌入表达式,非常方便。
moonbit
fn main {
let name = "ChenSuiYi"
let age = 18
let score = 98.5
// 基础插值
println("My name is \{name}")
// 插入表达式
println("Next year I'll be \{age + 1}")
// 多个变量
println("Name: \{name}, Age: \{age}, Score: \{score}")
}
字符串操作
moonbit
fn main {
let s = "Hello, World!"
// 转换为字符数组
let chars = s.to_array()
println(chars) // ['H', 'e', 'l', 'l', 'o', ...]
// 从字符数组创建字符串
let new_str = String::from_array(['M', 'o', 'o', 'n'])
println(new_str) // "Moon"
// 字符串比较
let is_same = "hello" == "hello" // true
let is_less = "apple" < "banana" // true (字典序)
}
Char (字符)
Char 表示一个 Unicode 码点(Code Point)。注意它与 Byte 的区别,Char 可以存储中文、Emoji 等任意 Unicode 字符。
基础用法
moonbit
fn main {
let c1 : Char = 'A'
let c2 : Char = '中'
let c3 : Char = '\u{1F600}' // Emoji 😀
let c4 : Char = '\u0041' // 'A' 的 Unicode 表示
println(c1)
println(c2)
println(c3)
}
字符与整数的转换
Char 可以与 Int 相互转换,这在处理字符编码时非常有用。
moonbit
fn main {
let ch : Char = 'A'
// Char 转 Int (获取 Unicode 码点)
let code : Int = ch.to_int()
println("'A' 的 Unicode: \{code}") // 65
// 字符运算 (字符字面量可重载为 Int)
let s = "hello"
let offset = s[0] - 'a' // 计算 'h' 相对于 'a' 的偏移
println("Offset: \{offset}") // 7
}
字符分类判断
moonbit
fn main {
fn is_digit(c : Char) -> Bool {
c >= '0' && c <= '9'
}
fn is_lowercase(c : Char) -> Bool {
c >= 'a' && c <= 'z'
}
fn is_uppercase(c : Char) -> Bool {
c >= 'A' && c <= 'Z'
}
println(is_digit('5')) // true
println(is_lowercase('m')) // true
println(is_uppercase('X')) // true
}
Byte & Bytes (字节与字节序列)
Byte 和 Bytes 是 MoonBit 中处理二进制数据的基础类型。
Byte: 单个字节 (0-255),用于处理二进制数据或 ASCII 字符Bytes: 不可变的字节序列,类似于其他语言的byte[]
Byte (单字节)
moonbit
fn main {
// ASCII 字符
let b1 : Byte = b'a'
println(b1.to_int()) // 97
// 十六进制转义
let b2 : Byte = b'\x41' // 'A'
println(b2.to_int()) // 65
// 八进制转义
let b3 : Byte = b'\o102' // 'B'
println(b3.to_int()) // 66
// 特殊值
let null_byte : Byte = b'\x00'
let max_byte : Byte = b'\xff' // 255
}
Bytes (字节序列)
moonbit
fn main {
// 字节序列字面量
let bs : Bytes = b"Hello"
// 访问单个字节
println(bs[0]) // 第一个字节
// 获取长度
println(bs.length()) // 5
// 从数组创建
let arr = [b'h', b'i']
let from_arr = @bytes.from_array(arr)
// 字节序列拼接
let b1 = b"Hello"
let b2 = b" World"
let combined = b1 + b2 // b"Hello World"
}
Bytes 的转义序列
Bytes 字面量支持以下转义序列:
| 转义序列 | 含义 |
|---|---|
\n, \r, \t, \b |
换行、回车、制表符、退格 |
\\ |
反斜杠 |
\x41 |
十六进制转义 (单字节) |
\o102 |
八进制转义 (单字节) |
moonbit
fn main {
let with_newline : Bytes = b"Line1\nLine2"
let with_hex : Bytes = b"\x48\x65\x6c\x6c\x6f" // "Hello"
// 使用 Buffer 构造 Bytes
let buf = @buffer.new()
buf.write_bytes(b"Hello")
buf.write_byte(b'!')
let result = buf.contents() // b"Hello!"
}
Byte vs Char 的区别
| 特性 | Byte |
Char |
|---|---|---|
| 大小 | 1 字节 (8 位) | 可变 (1-4 字节 UTF-8) |
| 值范围 | 0-255 | 所有 Unicode 码点 |
| 用途 | 二进制数据、ASCII | 文本字符、Unicode |
| 字面量 | b'x' |
'x' |
Tuple (元组)
元组是一个固定长度 、可以包含不同类型元素的集合。它是将多个值组合在一起的简单方式。
基础用法
moonbit
fn main {
// 定义一个包含 String, Int, Bool 的元组
let user = ("ChenSuiYi", 18, true)
// 通过索引访问 (使用 .0, .1, .2 ...)
println(user.0) // "ChenSuiYi"
println(user.1) // 18
println(user.2) // true
}
模式匹配解构
解构是访问元组元素的推荐方式,可以同时提取多个值:
moonbit
fn main {
let point = (10, 20)
let (x, y) = point // 解构
println("x: \{x}, y: \{y}")
// 忽略不需要的值
let data = ("name", 42, true, 3.14)
let (name, _, _, pi) = data // 使用 _ 忽略
println("name: \{name}, pi: \{pi}")
}
函数返回多个值
元组常用于函数需要返回多个值的场景:
moonbit
// 同时返回商和余数
fn div_mod(a : Int, b : Int) -> (Int, Int) {
(a / b, a % b)
}
// 返回最小值和最大值
fn min_max(a : Int, b : Int) -> (Int, Int) {
if a < b {
(a, b)
} else {
(b, a)
}
}
fn main {
let (quotient, remainder) = div_mod(17, 5)
println("17 / 5 = \{quotient}, remainder = \{remainder}")
let (min, max) = min_max(10, 3)
println("min: \{min}, max: \{max}")
}
元组的类型标注
moonbit
fn main {
// 显式类型标注
let pair : (String, Int) = ("Alice", 30)
let triple : (Int, Int, Int) = (1, 2, 3)
// 嵌套元组
let nested : ((Int, Int), String) = ((1, 2), "point")
let ((x, y), label) = nested
println("Point \{label}: (\{x}, \{y})")
}
元组 vs 结构体
| 特性 | 元组 | 结构体 |
|---|---|---|
| 字段访问 | 通过索引 (.0, .1) |
通过名称 (.name) |
| 可读性 | 较差 | 较好 |
| 适用场景 | 临时组合、简单数据 | 复杂数据结构 |
| 定义方式 | 无需定义 | 需要 struct 定义 |
Ref (可变引用)
在 MoonBit 中,默认变量绑定是不可变的 。如果你需要一个可变的值,可以使用 Ref[T]。它本质上是一个包含 val 字段的可变结构体。
基础用法
moonbit
fn main {
// 创建可变引用
let count : Ref[Int] = { val: 0 }
// 读取值
println(count.val) // 0
// 修改值
count.val = count.val + 1
println(count.val) // 1
// 复合赋值
count.val += 10
println(count.val) // 11
}
为什么需要 Ref?
MoonBit 的变量默认不可变,这有助于编写更安全的代码。但有时我们确实需要可变状态:
moonbit
fn main {
// 这样做不行!
// let mut x = 0 // MoonBit 没有 mut 关键字
// x = x + 1
// 正确方式:使用 Ref
let x : Ref[Int] = { val: 0 }
x.val = x.val + 1
}
实际应用:计数器
moonbit
fn make_counter() -> () -> Int {
let count : Ref[Int] = { val: 0 }
fn() {
count.val = count.val + 1
count.val
}
}
fn main {
let counter = make_counter()
println(counter()) // 1
println(counter()) // 2
println(counter()) // 3
}
共享可变状态
多个函数可以共享同一个 Ref:
moonbit
fn main {
let shared : Ref[Int] = { val: 100 }
fn add(n : Int) -> Unit {
shared.val = shared.val + n
}
fn sub(n : Int) -> Unit {
shared.val = shared.val - n
}
add(50)
println(shared.val) // 150
sub(30)
println(shared.val) // 120
}
Option & Result (选项与结果)
MoonBit 使用 Option 和 Result 来优雅地处理可能不存在的值和错误,而不是使用 null 或异常。这是现代编程语言的最佳实践。
Option - 处理可能缺失的值
Option[T] 表示一个值可能存在 (Some(v)) 或不存在 (None)。它可以简写为 T?。
moonbit
fn divide(a : Int, b : Int) -> Int? { // Int? 等价于 Option[Int]
if b == 0 {
None
} else {
Some(a / b)
}
}
fn main {
let result = divide(10, 2)
// 使用 match 处理
match result {
Some(v) => println("Result: \{v}")
None => println("Cannot divide by zero")
}
}
Option 的常用方法
moonbit
fn main {
let some_value : Int? = Some(42)
let no_value : Int? = None
// unwrap_or: 获取值,如果是 None 则返回默认值
let val1 = some_value.unwrap_or(0) // 42
let val2 = no_value.unwrap_or(0) // 0
// map: 转换 Some 中的值
let doubled = some_value.map(fn(x) { x * 2 }) // Some(84)
// filter: 根据条件过滤
let filtered = some_value.filter(fn(x) { x > 50 }) // None
// bind (flatMap): 链式操作
let chained = some_value.bind(fn(x) { Some(x + 10) }) // Some(52)
println("val1: \{val1}, val2: \{val2}")
}
is 表达式简化判断
MoonBit 提供了 is 表达式来简化 Option 的判断:
moonbit
fn main {
let opt : Int? = Some(42)
// 使用 is 表达式
if opt is Some(v) {
println("Value is \{v}")
}
// 配合 && 使用
if opt is Some(v) && v > 0 {
println("Positive value: \{v}")
}
}
Result - 处理可能的错误
Result[T, E] 用于表示操作成功 (Ok(v)) 或失败 (Err(e))。与 Option 不同,它可以携带错误信息。
moonbit
fn safe_div(a : Int, b : Int) -> Result[Int, String] {
if b == 0 {
Err("Division by zero")
} else {
Ok(a / b)
}
}
fn main {
match safe_div(10, 0) {
Ok(v) => println("Result: \{v}")
Err(msg) => println("Error: \{msg}")
}
}
Result 的常用方法
moonbit
fn main {
let ok_result : Result[Int, String] = Ok(42)
let err_result : Result[Int, String] = Err("something wrong")
// unwrap_or: 获取值或默认值
let val = err_result.unwrap_or(0) // 0
// map: 转换 Ok 中的值
let mapped = ok_result.map(fn(x) { x + 1 }) // Ok(43)
// map_err: 转换 Err 中的错误
let mapped_err = err_result.map_err(fn(e) { e + "!" }) // Err("something wrong!")
// to_option: 转换为 Option (丢弃错误信息)
let as_option = ok_result.to_option() // Some(42)
println("val: \{val}")
}
使用 raise 进行错误处理
MoonBit 还支持使用 raise 抛出错误,配合 try 捕获:
moonbit
fn divide_strict(a : Int, b : Int) -> Int raise {
if b == 0 {
raise Failure("Division by zero")
} else {
a / b
}
}
fn main {
// 使用 try! 获取值(失败时 panic)
let result1 = try! divide_strict(10, 2)
println("Result: \{result1}")
// 使用 try? 转换为 Result
let result2 = try? divide_strict(10, 0)
match result2 {
Ok(v) => println("OK: \{v}")
Err(_) => println("Division failed")
}
}
Option vs Result 对比
| 特性 | Option[T] | Result[T, E] |
|---|---|---|
| 用途 | 值可能不存在 | 操作可能失败 |
| 成功 | Some(value) |
Ok(value) |
| 失败 | None |
Err(error) |
| 错误信息 | 无 | 有 |
| 简写 | T? |
无 |
Array & FixedArray (数组)
MoonBit 提供两种数组类型:可变长度的 Array 和固定长度的 FixedArray。
Array (动态数组)
Array[T] 类似于其他语言的 List 或 Vector,可以动态添加/删除元素。
moonbit
fn main {
// 字面量创建
let arr = [1, 2, 3]
// 空数组创建
let empty : Array[Int] = Array::new()
// 添加元素
arr.push(4)
arr.push(5)
println(arr) // [1, 2, 3, 4, 5]
// 访问元素
println(arr[0]) // 1
// 修改元素
arr[0] = 100
println(arr[0]) // 100
// 获取长度
println(arr.length()) // 5
}
Array 的创建方式
moonbit
fn main {
// 1. 字面量
let arr1 = [1, 2, 3]
// 2. 使用 makei 根据索引创建
let arr2 = Array::makei(5, fn(i) { i * 2 }) // [0, 2, 4, 6, 8]
// 3. 从迭代器创建
let arr3 = Array::from_iter("hello".iter()) // ['h', 'e', 'l', 'l', 'o']
println(arr2)
println(arr3)
}
Array 常用操作
moonbit
fn main {
let arr = [1, 2, 3, 4, 5]
// map: 映射每个元素
let doubled = arr.map(fn(x) { x * 2 })
println(doubled) // [2, 4, 6, 8, 10]
// filter: 过滤元素
let evens = arr.filter(fn(x) { x % 2 == 0 })
println(evens) // [2, 4]
// fold: 累积计算
let sum = arr.fold(init=0, fn(acc, x) { acc + x })
println("Sum: \{sum}") // 15
// each: 遍历
arr.each(fn(x) { println(x) })
// contains: 检查是否包含
println(arr.contains(3)) // true
}
FixedArray (固定数组)
FixedArray[T] 长度固定,性能通常更高,适合已知大小的数据集。
moonbit
fn main {
// 显式声明为 FixedArray
let arr : FixedArray[Int] = [1, 2, 3]
// 使用类型转换语法
let arr2 = ([1, 2, 3] : FixedArray[Int])
// 使用 make 创建 (所有元素初始化为相同值)
let zeros = FixedArray::make(5, 0) // [0, 0, 0, 0, 0]
// 使用 makei 创建 (根据索引初始化)
let indices = FixedArray::makei(5, fn(i) { i }) // [0, 1, 2, 3, 4]
println(zeros)
println(indices)
}
⚠️ FixedArray 的常见陷阱
使用 make 创建嵌套数组时要小心,所有元素会引用同一个对象:
moonbit
fn main {
// ❌ 错误方式:所有行引用同一个数组!
let wrong = FixedArray::make(3, FixedArray::make(3, 0))
wrong[0][0] = 1
println(wrong[1][0]) // 1 (不是预期的 0!)
// ✅ 正确方式:使用 makei 为每行创建独立数组
let correct = FixedArray::makei(3, fn(_) {
FixedArray::make(3, 0)
})
correct[0][0] = 1
println(correct[1][0]) // 0 (正确!)
}
Array vs FixedArray 对比
| 特性 | Array[T] | FixedArray[T] |
|---|---|---|
| 长度 | 可变 | 固定 |
| 添加元素 | push() |
不支持 |
| 性能 | 稍慢 (需要管理容量) | 更快 |
| 内存 | 可能有额外空间 | 精确分配 |
| 适用场景 | 动态集合 | 已知大小的数据 |
ArrayView (数组视图)
ArrayView[T] 类似于其他语言中的 slice,它是对数组某个片段的引用,不会复制数据。
创建视图
moonbit
fn main {
let arr = [0, 1, 2, 3, 4, 5]
// 语法: arr[start:end] (不包含 end)
let view1 = arr[2:5] // [2, 3, 4]
let view2 = arr[:3] // [0, 1, 2] (从开头)
let view3 = arr[3:] // [3, 4, 5] (到结尾)
let view4 = arr[:] // [0, 1, 2, 3, 4, 5] (全部)
println(view1)
println(view2)
}
视图操作
moonbit
fn main {
let arr = [1, 2, 3, 4, 5]
let view = arr[1:4] // [2, 3, 4]
// 在视图上使用 map
let doubled = view.map(fn(x) { x * 2 })
println(doubled) // [4, 6, 8]
// 视图遍历
for x in view {
println(x)
}
}
⚠️ 注意事项
ArrayView 本身是不可变的,但底层数组可以被修改:
moonbit
fn main {
let arr = [1, 2, 3, 4, 5]
let view = arr[1:4] // [2, 3, 4]
// 修改原数组
arr[2] = 100
// 视图也会反映变化!
println(view) // [2, 100, 4]
}
Map (哈希映射)
Map[K, V] 是键值对的集合,MoonBit 的 Map 保留插入顺序(类似 Java 的 LinkedHashMap)。
基础用法
moonbit
fn main {
// 字面量创建
let scores = { "Alice": 100, "Bob": 90, "Charlie": 85 }
// 获取值 (返回 Option)
match scores.get("Alice") {
Some(score) => println("Alice's score: \{score}")
None => println("Not found")
}
// 获取值或默认值
let bob_score = scores.get_or_default("Bob", 0)
println("Bob's score: \{bob_score}")
}
Map 操作
moonbit
fn main {
let map : Map[String, Int] = {}
// 插入/更新
map.set("a", 1)
map.set("b", 2)
map["c"] = 3 // 简写语法
// 更新已存在的键
map.set("a", 10)
// 删除
map.remove("b")
// 检查键是否存在
let has_a = map.contains("a")
println("Has 'a': \{has_a}") // true
// 获取大小
println("Size: \{map.length()}") // 2
}
遍历 Map
moonbit
fn main {
let scores = { "Alice": 100, "Bob": 90 }
// 使用 for..in 遍历
for k, v in scores {
println("\{k}: \{v}")
}
// 使用 each 方法
scores.each(fn(k, v) {
println("Key: \{k}, Value: \{v}")
})
}
Map 模式匹配
MoonBit 支持在 Map 上进行模式匹配:
moonbit
fn check_config(config : Map[String, Int]) -> Unit {
match config {
{ "port": port, "timeout": timeout, .. } => {
println("Port: \{port}, Timeout: \{timeout}")
}
{ "port": port, .. } => {
println("Port: \{port}, using default timeout")
}
_ => println("Invalid config")
}
}
fn main {
let config = { "port": 8080, "timeout": 30 }
check_config(config)
}
Set (集合)
MoonBit 提供了 @hashset.HashSet 用于存储不重复的元素。
基础用法
moonbit
fn main {
// 创建集合
let set = @hashset.of([1, 2, 3, 4, 5])
// 添加元素
set.add(6)
// 移除元素
set.remove(1)
// 检查元素是否存在
println(set.contains(3)) // true
println(set.contains(1)) // false
// 获取大小
println(set.length()) // 5
}
集合运算
moonbit
fn main {
let set1 = @hashset.of([1, 2, 3, 4])
let set2 = @hashset.of([3, 4, 5, 6])
// 并集 (Union): 合并两个集合的所有元素
let union_set = set1.union(set2)
println(union_set.length()) // 6: [1, 2, 3, 4, 5, 6]
// 交集 (Intersection): 两个集合共有的元素
let intersection = set1.intersection(set2)
println(intersection.length()) // 2: [3, 4]
// 差集 (Difference): 在 set1 中但不在 set2 中的元素
let difference = set1.difference(set2)
println(difference.length()) // 2: [1, 2]
// 对称差集: 在 set1 或 set2 中,但不同时在两者中的元素
let sym_diff = set1.symmetric_difference(set2)
println(sym_diff.length()) // 4: [1, 2, 5, 6]
}
Json (JSON 支持)
MoonBit 对 JSON 有原生的一流支持,可以直接使用字面量创建 JSON 对象,无需额外的库。
创建 JSON
moonbit
fn main {
// 直接使用字面量创建 JSON
let user : Json = {
"name": "ChenSuiYi",
"age": 18,
"skills": ["MoonBit", "TypeScript", "Rust"],
"is_developer": true,
"profile": {
"github": "chensuiyi",
"website": "https://chensuiyi.me"
}
}
println(user)
}
JSON 模式匹配
MoonBit 支持对 JSON 进行模式匹配,非常方便地提取数据:
moonbit
fn parse_config(config : Json) -> Unit {
match config {
{ "name": name, "version": version, .. } => {
println("Package: \{name} v\{version}")
}
_ => println("Invalid config")
}
}
fn main {
let config : Json = {
"name": "my-package",
"version": "1.0.0",
"dependencies": {}
}
parse_config(config)
}
JSON 数组处理
moonbit
fn main {
let data : Json = {
"users": [
{ "name": "Alice", "age": 25 },
{ "name": "Bob", "age": 30 }
]
}
match data {
{ "users": [first, ..] } => {
match first {
{ "name": name, .. } => println("First user: \{name}")
_ => ()
}
}
_ => ()
}
}
重载字面量 (Overloaded Literals)
MoonBit 的一个独特特性是重载字面量:同一个字面量语法可以根据上下文的期望类型,自动转换为不同的类型。
数字字面量重载
moonbit
fn main {
// 同一个 42,根据类型标注变成不同类型
let int_val : Int = 42
let uint_val : UInt = 42
let int64_val : Int64 = 42
let double_val : Double = 42
let float_val : Float = 42
let bigint_val : BigInt = 42
println("All are 42, but different types!")
}
数组字面量重载
moonbit
fn main {
// 同一个 [1, 2, 3],可以是 Array 或 FixedArray
let array : Array[Int] = [1, 2, 3]
let fixed : FixedArray[Int] = [1, 2, 3]
// 字符数组可以重载为 String
let chars : String = ['H', 'e', 'l', 'l', 'o']
println(chars) // "Hello"
// 字节数组可以重载为 Bytes
let bytes : Bytes = [b'H', b'i']
}
字符字面量重载
moonbit
fn main {
// 字符可以重载为 Int (用于字符运算)
let s = "hello"
let offset = s[0] - 'a' // 'h' - 'a' = 7
// 也可以重载为 Byte
let b : Byte = 'A' // 65
}
字符串字面量重载
moonbit
fn main {
// 字符串可以重载为 Bytes
let bs : Bytes = "Hello"
println(bs.length()) // 5
}
重载字面量的好处:
- 代码更简洁,无需显式类型转换
- 类型安全,编译器会检查转换是否合法
- 提高可读性
迭代器 (Iterator)
MoonBit 的 Iter[T] 提供了一种统一、惰性的方式来遍历数据结构。
基础用法
moonbit
fn main {
let arr = [1, 2, 3, 4, 5]
// 获取迭代器
let iter = arr.iter()
// 常用操作
iter.each(fn(x) { println(x) })
}
链式操作
迭代器支持惰性的链式操作,非常高效:
moonbit
fn main {
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 链式操作:惰性求值,不会创建中间数组
let result = arr.iter()
.filter(fn(x) { x % 2 == 0 }) // 过滤偶数
.map(fn(x) { x * x }) // 平方
.collect() // 收集结果
println(result) // [4, 16, 36, 64, 100]
}
for...in 循环
for..in 循环底层使用迭代器:
moonbit
fn main {
let arr = [1, 2, 3]
// 遍历元素
for x in arr {
println(x)
}
// 遍历 Map 的键值对
let map = { "a": 1, "b": 2 }
for k, v in map {
println("\{k}: \{v}")
}
// 遍历范围
for i in 0..<5 {
println(i) // 0, 1, 2, 3, 4
}
for i in 0..=5 {
println(i) // 0, 1, 2, 3, 4, 5
}
}
总结
MoonBit 的内置数据结构设计得既实用又高效。从基础的 Unit、Bool 到强大的 Option、Result 错误处理机制,再到灵活的 Array 和 Map,它们共同构成了 MoonBit 编程的坚实基础。