MoonBit内置数据结构详解

改变世界的编程语言 MoonBit

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

往期文章

在上一篇文章中,我们对 MoonBit 的语法基础做了一个概览。今天,我们将深入探讨 MoonBit 中最基础也是最重要的部分------内置数据结构

数据结构是编程语言的基石,了解它们对于编写高效、正确的代码至关重要。MoonBit 提供了一套丰富且高效的内置数据结构,涵盖了从最基本的布尔值、数字到复杂的数组、映射等。

本文将带你逐一解析这些内置数据结构,并通过详细的代码示例帮助你掌握它们的用法。

本文目录

  1. Unit (单元类型)
  2. Bool (布尔值)
  3. Numbers (数字类型)
  4. String (字符串)
  5. Char (字符)
  6. Byte & Bytes (字节与字节序列)
  7. Tuple (元组)
  8. Ref (可变引用)
  9. Option & Result (选项与结果)
  10. Array & FixedArray (数组)
  11. ArrayView (数组视图)
  12. Map (哈希映射)
  13. Set (集合)
  14. Json (JSON 支持)
  15. 重载字面量 (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 (字节与字节序列)

ByteBytes 是 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 使用 OptionResult 来优雅地处理可能不存在的值和错误,而不是使用 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] 类似于其他语言的 ListVector,可以动态添加/删除元素。

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 的内置数据结构设计得既实用又高效。从基础的 UnitBool 到强大的 OptionResult 错误处理机制,再到灵活的 ArrayMap,它们共同构成了 MoonBit 编程的坚实基础。

相关推荐
小二·1 小时前
Spring框架入门:TX 声明式事务详解
java·数据库·spring
i02081 小时前
Java 17 + Spring Boot 3.2.5 使用 Redis 实现“生产者–消费者”任务队列
java·spring boot·redis
万邦科技Lafite1 小时前
一键获取淘宝店铺所有商品信息,实时监控商品数据
开发语言·数据库·python·api·开放api·电商开放平台·淘宝开放平台
SUPER52661 小时前
运维hbase服务重启,导致应用查询异常 hbase:meta
运维·数据库·hbase
烤麻辣烫1 小时前
黑马程序员苍穹外卖后端概览
xml·java·数据库·spring·intellij-idea
点灯小铭2 小时前
基于单片机的智能药物盒设计与实现
数据库·单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
非鱼feiyu2 小时前
自关联数据表查询优化实践:以 Django + 递归 CTE 构建树结构为例
数据库·后端·django
寻找华年的锦瑟2 小时前
Qt-QStackedWidget
java·数据库·qt
CodeByV3 小时前
【算法题】双指针(二)
数据结构·算法