马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
DST(dynamic size type)-中译“动态大小范例"。本文扼要讨论动态大小范例的一些题目。
一、前言
rust作为一门静态范例语言,和大部分其它静态范例语言(C,C++,C#,JAVA)一样,盼望在编译的时候知道每个实例/范例的大小。
作为静态范例语言,优点是毋庸置疑的的:
1.范例错误(如字符串与整数运算)在编译阶段即可被捕获,淘汰运行时崩溃风险
2.编译器可基于范例信息优化内存分配与代码实行效率
但无论哪一种静态范例语言,都有同样的题目:实际业务场景中,必然有动态大小的范例,那么应该如何处理了?
每个静态范例语言都有它的处理机制,但由于rust的设计哲学和目的,以是它的处理方式是非常特殊的!
无论如何,rust必须可以或许处理动态大小范例,否则这个语言无法用(或者变为极其难用的玩具)。
二、RUST动态范例
如前,rust也有动态范例,例如常见的str。
只是可惜的是,我们常用的其实是&str,留意不是str。假如直接let a:str="abc"是报告编译错误的:
doesn't have a size known at compile-time现在聊聊动态范例的几个题目.2.1、如何处理动态大小范例
rust使用了新范例设计模式(个人更乐意看作是封装模式)来解决这个题目。
具体而言就是用智能指针来解决这个题目。
如我们所知,智能指针的典型结构:一个指向数据的指针、少量的其它元数据、额外实现的一些特质(例如Deref,Drop).
因此,编译器会把智能指针视为一个固定大小。 是的,String也可以看作式某种智能指针。
我们来看经典的Box盒子指针的定义:- pub struct Box<
- T: ?Sized,
- #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
- >(Unique<T>, A);
- #[lang = "ptr_unique"]
- pub struct Unique<T: ?Sized> {
- pointer: NonNull<T>,
- // NOTE: this marker has no consequences for variance, but is necessary
- // for dropck to understand that we logically own a `T`.
- //
- // For details, see:
- // https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data
- _marker: PhantomData<T>,
- }
- pub struct NonNull<T: ?Sized> {
- pointer: *const T,
- }
- pub struct PhantomData<T: ?Sized>;
- #[unstable(feature = "allocator_api", issue = "32838")]
- pub unsafe trait Allocator {
- //此处略
- }
复制代码 留意,T是?Sized,意思T可以是固定大小或者动态大小。其次根据文档说明 ?T(T是特质)目前只能有?Sized,换言之,不会有?Drop,?Deref之类的申明。
在Box的底层通过 *const T(不可变原始指针)来指向实际的数据,整体上可以看作是固定大小的。
2.2、Sized特质
Sized特质,故名思意就是大小的意思,在rust中表示一个特质,表示被它绑定(限定)的范例是固定大小。rust编译器会为每一个添加了Sized特质的范例实现具体内容。
?Size则表树模例是可以固定也可以不是固定大小。其次根据文档说明 ?T(T是特质)目前只能有?Sized,换言之,不会有?Drop,?Deref之类的申明。
看看Box的定义就是知道范例是?Sized,而实践也告诉我们,可以在Box中存放标量范例和堆栈范例。
2.3、动态分发(dyn)
动态分发(dynamic dispatch),意思就是在运行的时候才确定特质对应的实际范例。
在编码的时候,假如使用指针存储一个特质,那么必须添加一个dyn,这样rustc通过编译,并在运行的时候,会把特质替换为实际的范例实例。
三、示例
[code]trait Animal { fn eat(&self);}struct Tiger { name: String, age: u8,}struct Pig { name: String, age: u8,}impl Animal for Tiger { fn eat(&self) { println!("{}岁{} 正在吃野猪", self.age, self.name); }}impl Animal for Pig { fn eat(&self) { println!("{}岁{} 正在吃竹笋和地瓜", self.age, self.name); }}impl Tiger { fn clone(&self) -> Tiger { Tiger { name: self.name.clone(), age: self.age, } }}fn feed_animal_dyn(animals: Vec) { for animal in animals { animal.eat(); }}/** * Sized特质测试,告知编译器这个参数可以是固定大小也可以是动态大小,而非固定大小 */fn feed_animal(animal: T)where T: Animal,{ animal.eat();}fn main() { //这样定义会报告编译错误:doesn't have a size known at compile-time //let me:str="lzf"; dst_test(); dyn_test(); sized_test();}fn sized_test() { let tiger = Tiger { name: "大王
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |