集合类型
实现状态: Array<T> / Set<T> / Dictionary<K,V> / Object 产品可用(Dictionary 仍为 String-shell,见下);HOF map/filter/reduce GA(三后端 parity);用户 Sequence/Iterator for-in 已实现(Phase 71);裸 Array(无类型参数)已删除(Phase 60)。产品诚实面已与本章方法表对齐(facade 裸签名处 + sema 参数化已旁注);OrderedSet 非产品 GA(ordered_set.sy 存在,host capabilities 全 unsupported)。余:单态化、真 HashMap<Value, Value> 键外壳。
SYX 提供四种内置集合:有序 Array<T>、去重 Set<T>、键值 Dictionary<K,V>、动态 Object。本章覆盖字面量、方法、迭代、IO 互转与类型约束。
数组 Array
Array<T> 是最常用的有序可变序列:
let nums: Array<Int> = [1, 2, 3]
let mixed: Array<Any> = [1, "a", true] // 需 Any 约束
let empty: Array<Int> = []
print(nums.count) // 3
print(nums[0]) // 1
nums[1] = 99 // ✅ 可变强类型: Phase 60 起禁止 裸
Array(必须带类型参数)。需要混合类型用Array<Any>或Object。
值语义:Array 赋值隔离(R-38 · SEM-ARRAY)
赋值 Array 后写时隔离(uniquify):
// prints: 1\n2
func main() {
var a = [1]
var b = a
b.append(2)
print(a.count)
print(b.count)
}常用方法
| 方法 | 签名 | 说明 |
|---|---|---|
.count | Int | 元素个数(空判断用 .count == 0,无 .isEmpty) |
.contains(item) | Bool | 是否包含(Equatable;无谓词版 .contains(where:)) |
.sorted() | Array<T> | 升序排序(新数组) |
.sortBy(comparator) | Array<T> | 自定义比较(facade 仍裸 Array / Function;≠ .sorted(by:)) |
.reverse() | Array<T> | 反转(新数组;真名 .reverse(),≠ .reversed()) |
.chunked(size) | Array<Array<T>> | 按长度切块(facade 仍 Array<Array>) |
.zip(other) | Array<Array<T>> | 与 other 成对(两侧同 T 时;否则 Array<Array<Object>>,≠ 静默 Array<Array<T>>;facade 仍裸 Array) |
.joined(sep:) | String | 用分隔符连接为字符串 |
.map(transform) | Array<U> | HOF(GA);U 由闭包结果类型推断(facade 仍 Function,≠ mono / map<U>) |
.filter(predicate) | Array<T> | HOF(GA);保留元素类型 T(facade 仍 Function) |
.reduce(initial, combine) | U | HOF(GA);U 由 initial 推断(facade 仍 initial: Int / -> Int / Function,≠ mono) |
.flatMap(transform) | Array<U> | HOF(GA);闭包结果为 Array<U> 时解开一层得 Array<U>,否则按单元素(facade 仍 Function,≠ mono) |
.append(item) | Void | 追加 |
另有 facade .binarySearch(仍 item: Int)。未实现(调用 → S002):.isEmpty、.first / .last、.reversed()、.remove(at:) / .removeAll()、.index(of:)、.slice、.contains(where:)、.allSatisfy、.forEach。遍历用 for。
数组字面量与推断
let a = [1, 2, 3] // 推断 Array<Int>
let b: Array<Float64> = [1.0, 2.0] // 显式
let c: Array<Int> = [] // 空数组必须标注或给初值高阶函数(HOF)
let nums = [1, 2, 3, 4, 5]
let doubled = nums.map({ x in x * 2 }) // [2, 4, 6, 8, 10]
let evens = nums.filter({ x in x % 2 == 0 }) // [2, 4]
let sum = nums.reduce(0, { acc, x in acc + x }) // 15HOF 走 __syx_array_map / __syx_array_filter / __syx_array_reduce Host 函数(详见 第 32 章);闭包参数是 Array<Element> 的元素 T。语义上 filter 结果为 Array<T>;map / flatMap 结果为 Array<U>;reduce 结果为 U(U 来自 initial)。将 Int→String 的 map 赋给 Array<Int>,或把 reduce(0, …) 赋给 String → S004。builtin facade 仍声明 Function / Array / reduce(…)->Int,不是全量单态化。
三后端 parity:
map/filter/reduce在 VM / 统一 MIR / WASM 三后端行为一致。测试fixtures/parity/hof.sy验证。
数组下标
var arr = [10, 20, 30]
print(arr[0]) // 10
arr[1] = 99 // ✅
print(arr) // [10, 99, 30]下标必须是 Int。越界读写(含负下标)→ 运行时错误 R003(文案含 out of bounds);不是返回 nil,也不是静默忽略写入。
Set
去重集合(基于 value_equals,保留插入顺序):
let s: Set<Int> = [1, 2, 3, 2] // 自动去重:{1, 2, 3}
print(s.count) // 3
print(s.contains(2)) // true| 方法 | 说明 |
|---|---|
.count | 元素个数(空判断用 .count == 0,无 .isEmpty) |
.contains(item) | 是否包含(要求 元素满足 Equatable) |
.insert(item) | 插入(已存在则忽略) |
.remove(item) | 是否删除成功(Bool;≠ Swift 式 Optional) |
.union(other) | 并集 |
.intersection(other) | 交集 |
未实现(调用 → S002):.isEmpty、.subtraction、.forEach。遍历用 for。
存储后端: 运行时是
Value::Set(Vec<Value>),按value_equals线性去重,保留插入顺序;.insert/.contains/.remove/.union/.intersection同一谓词。≠ 哈希表,≠ 用户hash(into:)。产品 facade 在packages/core/builtins/collections/set.sy(实例contains/insert/remove与 static 同走__syx_set_*Host)。
Dictionary 字典
类型与字面量均用 方括号 + 冒号,与数组 [T] / [elem, …] 区分:
let scores: [String: Int] = ["a": 1, "b": 2]
let byId: Dictionary<Int, Int> = {2: 4, 3: 6}
print(scores["a"]) // 1(Optional<Int>)
print(byId[2]) // 4(Optional<Int>)关键区分: 解析器见到
[key: value, …](首元素后跟:)即 Dictionary;见到[elem, …](首元素后跟,或])即 Array。两者语法不冲突。
存储后端(String-shell): 运行时
Value::Dict仍是HashMap<String, Value>(与Object同形)。String键直插槽;非String键(Int/ class 等)走内部\x1fsyx:编码的 key/value 槽。用户面.keys()/.count暴露逻辑键/条目数(解码后的Int等),不泄漏编码串。哈希相同且键不等时在该桶拉链并存(相等键替换值)。≠ 已完成的HashMap<Value, Value>真 Value 键外壳。产品 facade 在packages/core/builtins/collections/dictionary.sy(实例containsKey/keys/values/remove与 static 同走__syx_dict_*Host;facade 签名仍为裸Array/Object键,sema 返回Array<K>/Array<V>;赋值钉:dict_keys_values_type)。
常用方法
产品面(与 Core facade / dict Host 对齐;无 mapValues / merge / forEach / isEmpty):
| 方法 | 签名 | 说明 |
|---|---|---|
.count | Int | 键值对个数 |
.containsKey(k) | Bool | 是否包含键 |
.keys() | Array<K> | 键数组 |
.values() | Array<V> | 值数组 |
.remove(k) | Bool | 是否删除成功(≠ Swift 式 V?) |
d[k] / d[k] = v | 读/写 | 下标(见上) |
遍历与变换: 用
for k in d.keys()与下标取值;值侧 HOF(mapValues等)尚未提供——调用未知成员 → S002。
键类型约束
键类型 K 必须 满足 Hashable 协议:
let k1: [String: Int] = ["x": 1] // ✅ String: Hashable
let k2: [Int: String] = [1: "a", 2: "b"] // ✅ Int: Hashable
// let k3: [Array<Int>: Int] = [[1]: 1] // ❌ S004:Array<Int> not HashableHashable 与键语义:
data class+@Hashable:按字段合成哈希,可用作 Dict/Set 键。- 普通
class: Hashable作键:按实例身份(同一引用为同一键;字段相等 ≠ 同键)。- 用户写的
func hash(into:)/==不驱动 Dict/Set 查找;显式x.hash(into: h)只更新Hasher,与集合无关。
Dictionary 字面量键
let lit: [String: Int] = ["a": 1, "b": 2] // 字符串键
let byNum: [Int: String] = [1: "x", 2: "y"] // 整数键
let tuple: [String: Array<Int>] = ["xs": [1,2,3]]键为任意表达式(字面量、标识符、函数返回值等)。
Object(动态对象)
未标注的字典字面量推断为 Dictionary(value 须同质)。异质 JSON 袋须显式标注 Object(应尽量少用,优先具体类型):
let scores = ["a": 1, "b": 2] // Dictionary(同质)
let obj: Object = { "name": "SYX", "version": 110, "stable": true }
print(obj["name"]) // "SYX"
print(obj["version"]) // 110
print(obj["stable"]) // true| 形式 | 语法 | 类型 |
|---|---|---|
| Dictionary | ["a": 1] 或 [String: Int] = … | 同质键值(默认推断) |
| Object | let x: Object = { "k": v } | 动态异质袋(须标注) |
| 方法 | 签名 | 说明 |
|---|---|---|
obj[key] | Any? | 读取(Optional;与 valueForKey 同语义) |
obj[key] = v | Void | 写入(与 put 同语义) |
.valueForKey(key) | Object | 显式读键(object.sy facade) |
.put(key, value) | Object | 显式写键(返回袋自身) |
.count | Int | 键个数 |
.isEmpty | Bool | 空 |
.containsKey(key) | Bool | 是否包含键 |
.keys() | Array<String> | 键数组 |
.values() | Array<Object> | 值数组(类型擦除) |
.remove(key) | Bool | 是否删除成功(≠ V?) |
.description | String | 描述字符串 |
todo 4 soft-close(W1253 / ADR-1599): 默认字面量 → Dictionary;显式
: Object异构袋;上表方法面 met;钉todo4_object_soft_close_first_slice;项 4 不再开片。OUT:.merge;真HashMap<Value,Value>;Object 泛型深化;object_bag_ga。
无
.merge: Object / Dictionary 均尚未提供合并 API;手写下标拷贝(OUT / 不再以项 4 开片)。
类型擦除:
Object不带字段类型;读出值需用as?转换(详见 第 20 章)。.keys()经__syx_dict_keys,facade/sema 均为Array<String>;.values()经__syx_dict_values,facade/sema 均为Array<Object>(≠ 裸Array/ ≠Array<Int>)。
let obj: Object = { "name": "SYX", "version": 110, "stable": true }
let v = obj["version"]
if let n = v as? Int {
print("version is \(n)")
}自定义 Sequence / Iterator
Phase 71 起,用户自定义 class 实现 next() 即可被 for-in 遍历(三端 strict parity):
protocol Iterator {
func next() -> String?
}
class Counter: Iterator {
var current: Int
let end: Int
init(end: Int) { self.current = 0; self.end = end }
func next() -> String? {
if (current >= end) { return nil }
let s = "\(current)"
current = current + 1
return s
}
}
func main() {
let c = Counter(end: 3)
for s in c {
print(s) // 0, 1, 2
}
}协议要求: 自定义
Iterator必须有func next() -> String?(与 stdlib 一致);返回nil表示结束。详见 第 23 章 协议。
for-in 遍历
for x in iterable { … } 支持:
| iterable | 元素类型 | 说明 |
|---|---|---|
Array<T> | T | 顺序遍历 |
String | String(单标量) | 字素簇 |
Set<T> | T | 无序 |
Dictionary<K,V> | (K, V) 元组 | |
0..<n | Int | 半开范围 |
自定义 Iterator | String | Phase 71+ |
Object | (String, Any) 元组 | 键值对 |
Array<String>(File.readLines()) | String | 行 |
import System
for item in [1, 2, 3] { print(item) } // 1 2 3
for c in "abc" { print(c) } // a b c
for k in ["x": 1, "y": 2].keys() { print(k) } // x y
for i in 0..<3 { print(i) } // 0 1 2
for line in File.readLines("a.txt") { print(line) }二进制 IO(Phase 42 / 60)
import System 后整文件读写 Array 字节(元素为 UInt8):
import System
let path = "bytes.bin"
File.writeBytes(path, [0u8, 255u8, 42u8])
let bytes: Array<UInt8> = File.readBytes(path)
let h = FileHandle.open(path, "r")
let _ = FileHandle.read(h, 4096)
FileHandle.close(h)- 强类型: Phase 60 后必须
Array<UInt8>;裸Array报 S004。 - 大文件读
FileHandle流式;readBytes整文件加载到内存。
测试:stdlib/leak_file_stream.rs · stdlib/file_stream_watcher.rs
选择指南
| 需求 | 选 |
|---|---|
| 有序、可重复、可索引 | Array<T> |
| 去重、集合运算 | Set<T> |
| 静态键值映射、需编译期类型 | Dictionary<K, V> |
| 动态 JSON 风格、字段不固定 | Object(须显式标注;默认优先 Dictionary) |
| 字节流 | Array<UInt8> |
任意迭代、自定义 next() | class: Iterator |
性能与内存
Array<T>是值包装的Vec<T>引用;Array<UInt8>/Array<String>走ArrayBuild(VM HeapSlot,Phase 76)Dictionary<K, V>产品面走哈希语义;运行时仍是 String-shell(HashMap<String, Value>+ 非 String 键编码槽);字面量经materialize_dictHost 物化(Phase 77)Set<T>实现位于packages/core/builtins/collections/set.sy- 集合元素是 class 时,
arr.append(c)共享引用;不 深拷贝
诊断
| 代码 | 触发 | 修复 |
|---|---|---|
| S004 | Array 与 Dictionary 元素类型不一致 | 显式标注或修正字面量 |
| S010 | Dictionary 键类型不满足 Hashable | 改用 String/Int 或实现 Hashable |
| R003 | arr[i] 越界读写(含负下标) | 检查索引;≠ nil / 静默 |
| S024 | 集合 hosted op 禁止 legacy MethodCall(Phase 48) | 改用 extension / CallHost |
与 Swift 的差异
| 点 | SYX |
|---|---|
Array 写法 | [T] 与 Array<T> 等价 |
裸 Array | 已删除(Phase 60);必须带类型参数 |
| Dictionary 类型 | [String: Int] 或 Dictionary<String, Int> |
| Dictionary 字面量 | ["a": 1](方括号);Swift 仅 { } |
| Object | let o: Object = { "k": v }(须标注;未标注→Dictionary) |
| Dictionary 键 | 须 满足 Hashable(Int、String 等) |
Set 字面量 | [1, 2, 3] 显式标注为 Set<Int> |
flatMap | 已实现(Array<Array<T>> 扁平化) |
Range(半开) | 0..<n(已实现);闭区间 0...n 部分实现 |
KeyPath 数组 | \Array.[0](Phase 48);详见 第 13 章 |
下一章 → 控制流