您好,欢迎来到微智科技网。
搜索
您的当前位置:首页Rust杂记

Rust杂记

来源:微智科技网


前言

提示:本文旨在记录一些本人在学习Rust中遇到的一些零碎的知识点,暂时不知道如何做知识分类,不成体系,读者可以选择行忽略:


小知识点

不能单独实现Copy,想要实现Copy必须连同Clone一起实现,推测Copy的实现是建立在Clone上的,而Clone可以单独被实现,各位读者可以自行测试。

形象化认识实现了Copy Trait和未实现Copy Trait的对象赋值的区别

Copy Trait 演示动图

Rust 中非CopyTrait的对象赋值时所有权转移动画

Rust中数组是有类型,类型格式形如 [i32;3]. 值得注意的是:[i32;3]与[i32;4] 不是一个类型

已知数组根据内部元素的类型和数量,会形成不同具体的类型,具体数组类型是否实现Copy Trait 取决于内部元素是否实现Copy Trait,满足条件,编译器会自动实现Copy Trait;相对地,struct实现Copy Trait必须程序员显式进行声明,并且满足保证内部元素(字段)全都实现Copy Trait这一条件;

枚举变体内变量 在if语句中需要使用let语句提示;在match里面不需要

在Rust中,dyn MyTrait 与·impl MyTrait是什么意思,有什么区别

值得注意的是,dyn MyTrait出现在结构体的字段当中;而impl MyTrait出现在方法的参数中

	trait Chinese{
		//	10月1号 国庆放假
		fn celebrate_on_10.1 ();
	}
	//一个公司只招中国人
	struct Company{
		employee_nation:dyn Chinese //值得注意的是这里 使用了dyn Chinese
	}
	impl Company {
		emloy_someone(someone:impl Chinese)//值得注意的是这里 使用了impl Chinese
		{
			...
		}
	}

各位可以自行测试一下 ,互相颠倒使用dyn和impl,编译器会报错。
这时候我们会发现,dyn和impl区别是什么,是一个值得探讨的问题。
首先我们认识,在C#和Java当中,允许Interface v= new Implement(); 这种多态语句的,这是面向对象的设计; 而Rust的则不允许;内存中的分配对象let v:Struct=Struct{} ,即等式左边不是指针与对象,而是指v就是Struct本身(注意:此处Trait本质上是一个指针);在这个基础上如何实现实多态呢? Rust中的多态是有性的,只能是作为struct的字段存在,也就是说dyn Trait就是一个虚表,这个虚表指向了一个具体的实例;let v=Struct{iner:StructImpleteTrait} 此时Struct的大小确定了,到时候用到iner字段了通过虚表 会指向具体的实例;简而言之:dyn Trait是一个指针;很多人可能会想,为什么不把dyn Trait简化成 Trait。我猜想是设计者想让我们了解这个指针的动态性质吧。
现在轮到impl Trait,主要为了实现函数多态。我们先讲C#中函数的多态

Interce IAnimal{

}
class Cat{

}

class MyClass{
//此处的函数参数实现了多态
    public void DoSomething (IAnimal animal){
   	 ...
    }
} 

前面已经说了 接口是一个虚表,调用的时候把Cat对象或者其他实现中IAnimal的虚表传入,就是实现了多态;如果Rust可以是同样的设计,此处的IAnimal 应该替换成dyn Trait书,但实际上Rust用的impl Trait ,Impl提示我们此处传入是具体的实现,不再是虚表了;聪明的你应该已经想到了,是编译器根据具体调用传入,针对这个对象编译一个新的方法,这个发生在编译时;好处就是,运行时没有任何的性能损耗。

显式声明的两种方法数据类型的两种方法

clone这个方法的编译器的类型推断逻辑

先看现象:

Rust项目依赖的两种方式

关于枚举

数值集合枚举(Unit-Like Enums)


数值型枚举第一个必须默认是0,需要指定其他数值需要显式指明;
第二个数值在第一个的基础上累加,依此类推。
由于第二个必须比第二个数值大,所以除了第一个,其他变体不能为0。

数值型枚举直接转化成数值

数据携带枚举 Data-Carrying Enums


容器型枚举是指,每个变体可以某个数据类型的容器(如i23),容器型和数据型是对立的,不能出现在同一个枚举中。

智能指针

impl<T: ?Sized> Deref for &T {
    type Target = T;
    fn deref(&self) -> &T {
        *self
    }
}
  1. 自动解引用或者说内存穿透的作用,应用于如下场合:
 let mut mystr=Box::new(String::from("hello"));
 mystr.push_str("123");

其中push_str()这个方法,属于String这个对象,而使用Box的对象能够调用。等等,前文我们不是说,会递归解引用最后一个引用吗?那这里应该是递归到&str结束。让我们来纠正一下,其实不需要递归到&str,编译器会判断push_str属于String这个对象,Sting这个智能指针就停止了。
我们有如下结论,自动接引用是方便程序员调用引用链条中某一环节的方法;
另一个场景是函数入参的时候自动解引用

	     let mut mystr=Box::new(String::from("hello"));
        fn auto_deref (str: &str) {}
        //auto_deref(mystr);//没有使用&,不会触发接引用,会报错
        auto_deref(&mystr);//加上引用符号不会报错
        
        //auto_deref(String::from("1"));//没有使用&,不会触发接引用,会报错
        auto_deref(&String::from("1"));

明明是auto_deref函数定义的参数类型为&str,mystr是Box,但是我们可以通过给引用Box(看似多了一层引用,实际上引用遇到智能指针,触发了自动解开引用)获得了&str。
另外,通过这个案例就能明白,我们在学习Rust一开始就会有的疑惑:为什么fn func_name(str:&str)这样的函数签名可以接受func_name(&String::from("111")),答案就是自动解开引用;

值得注意的是,自动解引用的痛点在于解引用的最后,还是的形式是&val,如果想让而Box::new(Box::new(1)),如果想要实现内部数据+1,+是属于1本身方法 ,而不是&1的方法, 所以修改内部数据,必须使用*,在*参与的情况下,没有自动解引用。如果你必须利用自动解引用的特性的话。就得利用函数入参数自动解引用的特性,转门为自动解引用写一个方法。

Box

rust中使用关键字box 指定内存到堆中
//rust中使用关键字box 指定内存到堆中
let a=box 1;
智能指针Box内部使用了box关键字;如果对象没有创建,则会直接分配到堆中; 如果对象已经创建在栈中,则会将对象剪切到堆中;
Box会对数据对象产生独占效应。

结构体可以没有体「{}」

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- 7swz.com 版权所有 赣ICP备2024042798号-8

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务