rust高级话题
前言
每一种语言都有它比较隐秘的点。rust也不例外。
零大小类型ZST
struct Foo; //类单元结构
struct Zero(
(), //单元类型
[u8;0], //0大小的数组
Foo,
);//零大小类型组成的类型
动态大小类型DST
无法静态确定大小或对齐的类型。
特征对象trait objects:dyn Mytrait
切片slices:[T]、str
特征包含vtable,通过vtable访问成员。切片是数组或Vec的一个视图。
也许你会产生好奇,为什么字符串和特征不能像一般语言设计的那样,设计成一个指针就好,而弄成一个动态大小的类型。这和普通指针有什么不同?
从程序员的角度出发,所谓动态大小类型是不存在的,因为你不能构造一个动态大小类型的对象出来,不管如何你只能构造"动态大小类型的指针"。动态大小类型更像是一个思维过程的中间产物。
注意,动态大小类型的指针和普通指针是不同的:
动态大小类型指针是胖指针,有地址,还有大小,也就是多维的。
如&str 可以想象成:
&str{
ptr:*u8,
size:usize,
}
既然如此,那么解引用*&str就是无意义的,因为它丢失了对象的大小。这个角度去理解动态大小类型,或者比较具体。
rust中的动态大小类型,其本质是将原本对象中的大小信息,直接放到指针里面,形成一个胖指针,而对象自身是不包含大小的。这是合理的,比如c语言中的字符串,本质就是一个\0结束的字符串序列而已,并不包含什么大小字段,也不可能要求所有字符串都要带一个大小的字段。
为了类型安全,大小信息又是必要的,因而对这类基础类型做一个抽象,然后用胖指针来指向,不失为一个合理方案。
特征对象的指针也是如此,rust中作为一个胖指针来实现,因此特征对象本身就成了无法构造的动态大小类型了。
对于特征对象,rust有两个特殊关键字支撑其行为(impl 和 dyn):
impl 静态分发,泛型技术。(不要和impl xxx for y搞混)
dyn 动态分发,即指针。(用dyn能更好的对应静态分发的写法)
trait S{fn so(&self);};
impl S for i32{fn so(&self){println!("i32");}}
impl S for &str{fn so(&self){println!("&str");}}
//静态分发,0成本
fn f(a:impl S)->impl S{
a.so();
1
}
f("hi").so();
//动态分发,少量代价
fn f2(a:&dyn S)->&dyn S{
a.so();
&"hi"
}
f2(&1).so();
正确的安装方法
rust是一个快速变化的语言和编译系统,建议用最新版,否则可能出现兼容性问题而无法通过编译。
rustup 管理工具链的版本,分别有三个通道:nightly、beta、stable。如上所述,建议同时安装nightly版本,保持最新状态。
wget -O- https://sh.rustup.rs |sh #下载安装脚本并执行
安装之后,就可以用rustup命令来控制整个工具链的更新了。
rustup toolchain add nightly #安装每夜版本的工具链
rustup component add rust-src #安装源代码
cargo +nightly install racer #用每夜版本的工具链安装racer,一个代码补全的工具。因为当前只支持每夜版本
rustup component add rls # 这是面向编辑器的一个辅助服务
rustup component add rust-analysis #分析工具
#vscode : 搜索插件rls安装即可
结构体
struct 结构体是一种记录类型。成员称为域field,有类型和名称。也可以没有名称,称为元组结构tuple strcut。 只有一个域的特殊情况称为新类型newtype。一个域也没有称为类单元结构unit-like struct。
类别
域名称
域个数
写法举例
一般结构
有
>1
strcut S{x:i32,y:&str}
元组结构
无
>1
strcut S(i32,&str)
新类型
无
1
struct S(i32)
类单元结构
无
0
struct S
枚举和结构是不同的,枚举是一个集合(类似c语言种的联合union,变量的枚举成员可选,而不是全体成员),而结构是一个记录(成员必定存在)。
作为一个描述力比较强的语法对象,结构很多时候都在模拟成基础类型,但是更多时候是具备和基础类型不同的特征,而需要由用户来定制它的行为。
#[derive(Copy,Clone,Debug)] //模拟基础数据类型的自动复制行为,Debug 特征是为了打印输出
struct A;
let a = A;
let b = a;//自动copy 而不是move
println!("{:?}", a);//ok
复制和移动
rust的基本类型分类可以如此安排:
有所有权
默认实现copy
基本数据类型
元素实现copy的复合类型
数组