rust学习二十.12、RUST动态大小范例DST以及Sized特质

打印 上一主题 下一主题

主题 1716|帖子 1716|积分 5148

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

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盒子指针的定义:
  1. pub struct Box<
  2.     T: ?Sized,
  3.     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
  4. >(Unique<T>, A);
  5. #[lang = "ptr_unique"]
  6. pub struct Unique<T: ?Sized> {
  7.     pointer: NonNull<T>,
  8.     // NOTE: this marker has no consequences for variance, but is necessary
  9.     // for dropck to understand that we logically own a `T`.
  10.     //
  11.     // For details, see:
  12.     // https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data
  13.     _marker: PhantomData<T>,
  14. }
  15. pub struct NonNull<T: ?Sized> {
  16.     pointer: *const T,
  17. }
  18. pub struct PhantomData<T: ?Sized>;
  19. #[unstable(feature = "allocator_api", issue = "32838")]
  20. pub unsafe trait Allocator {
  21.     //此处略
  22. }
复制代码
留意,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企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

伤心客

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表