铁锈写个单链表都是地狱级硬核操作(二)
在本文写作时间内,构建单链表的操作依然没有搞定。不过过程中也收获了许多知识点,很多可以说是完全新鲜的概念。记录在本文内。
构建一个静态的单链表比较简单,但其中也涉及一些基础问题:空引用,递归定义等等。
空引用
铁锈语言没有预定义的空引用(没有 null
或者 nil
!)。比如定义一个结构体 Person,通过借用符号 &
对该类型进行引用:
struct Person {
name: String,
age: i32,
}
let a = Person { name: "dave", age: 18 };
let b: &Person = &a; // 引用了某 Person 值
可惜没有办法来表示 Person 类型的空值引用:
let a_null_ref: &Person = nil; // 没有预定义的空引用
这样也不行:
let a_null_ref: &Person; // 可以在后期给该变量赋值,但是不能直接使用这个变量作为空值。否则编译错误:未初始化!
空值引用在很多场合必不可少,比如单链表的尾节点。
铁锈语言的常规操作是利用枚举类型来实现同样的效果。由于枚举在铁锈语言中得到了加强,程序员可以用匿名结构体绑定枚举值,用这种枚举值的定义来取代结构体定义,还可以捎上一个枚举值表示该类型的空值:
enum Person {
Valued { name: String, age: i32 }, // 有值
Nil, // 空值
}
let a = &Person::Valued { name: String::from("dave") }; // 引用某个值
let b = &Person::Nil; // 引用该类型的空值
递归定义
链表的节点就是一个递归定义的数据结构:
节点 = (数据,&下一个节点)
回顾铁锈语言的类型系统的特性:
- 所有类型默认都是分配在栈上
- 分配在栈上的类型,其占用内存大小必须编译期已知
因此如果像下方代码定义一个递归的类型,是不可以的:
struct Node {
val: i32,
next: Node,
}
因为这样的话,该结构体占用空间未知,根据节点数量,可能是无穷大。